initial commit

This commit is contained in:
2026-09-21 13:41:40 +09:00
commit 855c7328df
411 changed files with 85352 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""Deterministic authored ZIP inputs for the bounded-input expansion guard."""
import hashlib
import json
from pathlib import Path
import struct
import zlib
ROOT = Path(__file__).resolve().parent
def build(output_size: int, padded_size: int | None = None) -> tuple[bytes, dict]:
plain = b"x" * output_size
compressor = zlib.compressobj(9, zlib.DEFLATED, -15)
compressed = compressor.compress(plain) + compressor.flush()
payload = compressed if padded_size is None else compressed.ljust(padded_size, b"\0")
name = b"index.html"
crc = zlib.crc32(plain)
local = struct.pack("<IHHHHHIIIHH", 0x04034B50, 20, 0x800, 8, 0, 33,
crc, len(payload), len(plain), len(name), 0)
central = struct.pack("<IHHHHHHIIIHHHHHII", 0x02014B50, (3 << 8) | 20,
20, 0x800, 8, 0, 33, crc, len(payload), len(plain),
len(name), 0, 0, 0, 0, 0o100600 << 16, 0) + name
offset = len(local) + len(name) + len(payload)
end = struct.pack("<IHHHHIIH", 0x06054B50, 0, 0, 1, 1, len(central), offset, 0)
archive = local + name + payload + central + end
return archive, {
"output_bytes": len(plain), "deflate_stream_bytes": len(compressed),
"zip_declared_compressed_bytes": len(payload),
"sha256": hashlib.sha256(archive).hexdigest(),
"output_sha256": hashlib.sha256(plain).hexdigest(),
}
def main() -> None:
manifest = {"generator": "generate.py; Python stdlib zlib, raw DEFLATE",
"content": "Authored repeated ASCII x; no external material or fonts.", "files": {}}
for name, size, padded, expectation in [
("padded-33mib.zip", 33 * 1024 * 1024, 256 * 1024, "open succeeds; extraction E_ARCHIVE_LIMIT before more than 32 MiB is sent"),
("threshold-32mib.zip", 32 * 1024 * 1024, None, "open and extraction succeed; ratio threshold is strictly greater than 32 MiB"),
("unpadded-33mib.zip", 33 * 1024 * 1024, None, "open E_ARCHIVE_LIMIT from metadata preflight"),
]:
archive, info = build(size, padded)
(ROOT / name).write_bytes(archive)
manifest["files"][name] = info | {"expected": expectation}
(ROOT / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n")
if __name__ == "__main__":
main()
+30
View File
@@ -0,0 +1,30 @@
{
"generator": "generate.py; Python stdlib zlib, raw DEFLATE",
"content": "Authored repeated ASCII x; no external material or fonts.",
"files": {
"padded-33mib.zip": {
"output_bytes": 34603008,
"deflate_stream_bytes": 33647,
"zip_declared_compressed_bytes": 262144,
"sha256": "fd84b25c229191d4efb24939c14a20506ea442e4becf2164d034a4bdc983291a",
"output_sha256": "7d641a2a7b1c449f586b444bd47a2005d83be0e142596f6d1a52da9c2256c96b",
"expected": "open succeeds; extraction E_ARCHIVE_LIMIT before more than 32 MiB is sent"
},
"threshold-32mib.zip": {
"output_bytes": 33554432,
"deflate_stream_bytes": 32617,
"zip_declared_compressed_bytes": 32617,
"sha256": "2f49d2152f9d10daad3109eecb532bd3e2c720f15708f1c1338c14785b7d7ef1",
"output_sha256": "05f052c8f6da8ee5228ec291820b559c4be183773b9e97a6b82e30dacff85dd3",
"expected": "open and extraction succeed; ratio threshold is strictly greater than 32 MiB"
},
"unpadded-33mib.zip": {
"output_bytes": 34603008,
"deflate_stream_bytes": 33647,
"zip_declared_compressed_bytes": 33647,
"sha256": "205c8ef001b932dc20cc0672bb515f72420202c5a147de7a6b8496439745ea5c",
"output_sha256": "7d641a2a7b1c449f586b444bd47a2005d83be0e142596f6d1a52da9c2256c96b",
"expected": "open E_ARCHIVE_LIMIT from metadata preflight"
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+348
View File
@@ -0,0 +1,348 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 38 /Kids [6 0 R 8 0 R 10 0 R 12 0 R 14 0 R 16 0 R 18 0 R 20 0 R 22 0 R 24 0 R 26 0 R 28 0 R 30 0 R 32 0 R 34 0 R 36 0 R 38 0 R 40 0 R 42 0 R 44 0 R 46 0 R 48 0 R 50 0 R 52 0 R 54 0 R 56 0 R 58 0 R 60 0 R 62 0 R 64 0 R 66 0 R 68 0 R 70 0 R 72 0 R 74 0 R 76 0 R 81 0 R 83 0 R] >>
endobj
3 0 obj
<< /Length 63 /Type /XObject /Subtype /Form /BBox [0 0 32 16] /Matrix [2 0 0 3 7 11] /Resources << /ExtGState << /Opaque << /Type /ExtGState /ca 1 /CA 1 >> >> >> >>
stream
q /Opaque gs 1 0 0 rg 0 0 16 16 re f 0 0 1 rg 16 0 16 16 re f Q
endstream
endobj
4 0 obj
<< /Length 23 /Type /XObject /Subtype /Form /BBox [0 0 32 16] /Resources << >> >>
stream
0 1 0 rg 0 0 32 16 re f
endstream
endobj
5 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 8 /Contents (generated-link flags 8) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
6 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [5 0 R] >>
endobj
7 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 8 /Contents (generated-link flags 8) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
8 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [7 0 R] >>
endobj
9 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 8 /Contents (generated-link flags 8) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
10 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [9 0 R] >>
endobj
11 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 8 /Contents (generated-link flags 8) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
12 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [11 0 R] >>
endobj
13 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 16 /Contents (generated-link flags 16) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
14 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [13 0 R] >>
endobj
15 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 16 /Contents (generated-link flags 16) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
16 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [15 0 R] >>
endobj
17 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 16 /Contents (generated-link flags 16) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
18 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [17 0 R] >>
endobj
19 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 16 /Contents (generated-link flags 16) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
20 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [19 0 R] >>
endobj
21 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /Contents (generated-link flags 24) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
22 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [21 0 R] >>
endobj
23 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /Contents (generated-link flags 24) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
24 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [23 0 R] >>
endobj
25 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /Contents (generated-link flags 24) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
26 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [25 0 R] >>
endobj
27 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /Contents (generated-link flags 24) /A << /S /URI /URI (https://example.org/flags) >> /C [1 0 0] /BS << /W 2 /S /S >> >>
endobj
28 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [27 0 R] >>
endobj
29 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 8 /Contents (stored-link flags 8) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
30 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [29 0 R] >>
endobj
31 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 8 /Contents (stored-link flags 8) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
32 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [31 0 R] >>
endobj
33 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 8 /Contents (stored-link flags 8) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
34 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [33 0 R] >>
endobj
35 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 8 /Contents (stored-link flags 8) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
36 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [35 0 R] >>
endobj
37 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 16 /Contents (stored-link flags 16) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
38 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [37 0 R] >>
endobj
39 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 16 /Contents (stored-link flags 16) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
40 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [39 0 R] >>
endobj
41 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 16 /Contents (stored-link flags 16) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
42 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [41 0 R] >>
endobj
43 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 16 /Contents (stored-link flags 16) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
44 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [43 0 R] >>
endobj
45 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /Contents (stored-link flags 24) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
46 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [45 0 R] >>
endobj
47 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /Contents (stored-link flags 24) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
48 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [47 0 R] >>
endobj
49 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /Contents (stored-link flags 24) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
50 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [49 0 R] >>
endobj
51 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /Contents (stored-link flags 24) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
52 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [51 0 R] >>
endobj
53 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 8 /Contents (stored-comment flags 8) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
54 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [53 0 R] >>
endobj
55 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 8 /Contents (stored-comment flags 8) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
56 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [55 0 R] >>
endobj
57 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 8 /Contents (stored-comment flags 8) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
58 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [57 0 R] >>
endobj
59 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 8 /Contents (stored-comment flags 8) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
60 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [59 0 R] >>
endobj
61 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 16 /Contents (stored-comment flags 16) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
62 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [61 0 R] >>
endobj
63 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 16 /Contents (stored-comment flags 16) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
64 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [63 0 R] >>
endobj
65 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 16 /Contents (stored-comment flags 16) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
66 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [65 0 R] >>
endobj
67 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 16 /Contents (stored-comment flags 16) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
68 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [67 0 R] >>
endobj
69 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 24 /Contents (stored-comment flags 24) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
70 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [69 0 R] >>
endobj
71 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 24 /Contents (stored-comment flags 24) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
72 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << >> /Annots [71 0 R] >>
endobj
73 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 24 /Contents (stored-comment flags 24) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
74 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << >> /Annots [73 0 R] >>
endobj
75 0 obj
<< /Type /Annot /Subtype /Stamp /Rect [42 48 74 64] /F 24 /Contents (stored-comment flags 24) /A << /S /URI /URI (https://example.org/flags) >> /AP << /N << /On 3 0 R /Off 4 0 R >> >> /AS /On >>
endobj
76 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << >> /Annots [75 0 R] >>
endobj
77 0 obj
<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /C [1 0 0] /BS << /W 2 >> >>
endobj
78 0 obj
<< /Type /Annot /Subtype /Link /Rect [41 47 75 65] /F 24 /AP << /N 4 0 R >> >>
endobj
79 0 obj
<< /Type /Annot /Subtype /Link /Rect [20 80 36 96] /F 26 /Contents (Invisible comment) /AP << /N 3 0 R >> >>
endobj
80 0 obj
<< /Type /Annot /Subtype /Link /Rect [80 80 96 96] /F 56 /Contents (Invisible comment) /AP << /N 3 0 R >> >>
endobj
81 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [77 0 R 78 0 R 79 0 R 80 0 R] >>
endobj
82 0 obj
<< /Type /Annot /Subtype /Link /Rect [108 48 140 64] /F 24 /AP << /N 3 0 R >> >>
endobj
83 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << >> /Annots [82 0 R] >>
endobj
xref
0 84
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000380 00000 n
0000000641 00000 n
0000000779 00000 n
0000000970 00000 n
0000001108 00000 n
0000001299 00000 n
0000001438 00000 n
0000001629 00000 n
0000001770 00000 n
0000001962 00000 n
0000002104 00000 n
0000002298 00000 n
0000002438 00000 n
0000002632 00000 n
0000002773 00000 n
0000002967 00000 n
0000003109 00000 n
0000003303 00000 n
0000003445 00000 n
0000003639 00000 n
0000003779 00000 n
0000003973 00000 n
0000004114 00000 n
0000004308 00000 n
0000004450 00000 n
0000004644 00000 n
0000004786 00000 n
0000004991 00000 n
0000005131 00000 n
0000005336 00000 n
0000005477 00000 n
0000005682 00000 n
0000005824 00000 n
0000006029 00000 n
0000006171 00000 n
0000006378 00000 n
0000006518 00000 n
0000006725 00000 n
0000006866 00000 n
0000007073 00000 n
0000007215 00000 n
0000007422 00000 n
0000007564 00000 n
0000007771 00000 n
0000007911 00000 n
0000008118 00000 n
0000008259 00000 n
0000008466 00000 n
0000008608 00000 n
0000008815 00000 n
0000008957 00000 n
0000009166 00000 n
0000009306 00000 n
0000009515 00000 n
0000009656 00000 n
0000009865 00000 n
0000010007 00000 n
0000010216 00000 n
0000010358 00000 n
0000010569 00000 n
0000010709 00000 n
0000010920 00000 n
0000011061 00000 n
0000011272 00000 n
0000011414 00000 n
0000011625 00000 n
0000011767 00000 n
0000011978 00000 n
0000012118 00000 n
0000012329 00000 n
0000012470 00000 n
0000012681 00000 n
0000012823 00000 n
0000013034 00000 n
0000013176 00000 n
0000013278 00000 n
0000013373 00000 n
0000013498 00000 n
0000013623 00000 n
0000013784 00000 n
0000013881 00000 n
trailer
<< /Size 84 /Root 1 0 R >>
startxref
14021
%%EOF
+464
View File
@@ -0,0 +1,464 @@
{
"generator": "generate_annotation_flags.py",
"license": "Self-created test content; same license as DocView.",
"sha256": "ec4a93fab82fd79efa2c8d9de5a83ad64350d7d02c061638ceda06007e1b8d4c",
"cropBox": [
8,
12,
120,
116
],
"cases": [
{
"page": 0,
"intrinsicRotation": 0,
"kind": "generated-link",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 1,
"intrinsicRotation": 90,
"kind": "generated-link",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 2,
"intrinsicRotation": 180,
"kind": "generated-link",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 3,
"intrinsicRotation": 270,
"kind": "generated-link",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 4,
"intrinsicRotation": 0,
"kind": "generated-link",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 5,
"intrinsicRotation": 90,
"kind": "generated-link",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 6,
"intrinsicRotation": 180,
"kind": "generated-link",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 7,
"intrinsicRotation": 270,
"kind": "generated-link",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 8,
"intrinsicRotation": 0,
"kind": "generated-link",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 9,
"intrinsicRotation": 90,
"kind": "generated-link",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 10,
"intrinsicRotation": 180,
"kind": "generated-link",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 11,
"intrinsicRotation": 270,
"kind": "generated-link",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 12,
"intrinsicRotation": 0,
"kind": "stored-link",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 13,
"intrinsicRotation": 90,
"kind": "stored-link",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 14,
"intrinsicRotation": 180,
"kind": "stored-link",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 15,
"intrinsicRotation": 270,
"kind": "stored-link",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 16,
"intrinsicRotation": 0,
"kind": "stored-link",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 17,
"intrinsicRotation": 90,
"kind": "stored-link",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 18,
"intrinsicRotation": 180,
"kind": "stored-link",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 19,
"intrinsicRotation": 270,
"kind": "stored-link",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 20,
"intrinsicRotation": 0,
"kind": "stored-link",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 21,
"intrinsicRotation": 90,
"kind": "stored-link",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 22,
"intrinsicRotation": 180,
"kind": "stored-link",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 23,
"intrinsicRotation": 270,
"kind": "stored-link",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 24,
"intrinsicRotation": 0,
"kind": "stored-comment",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 25,
"intrinsicRotation": 90,
"kind": "stored-comment",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 26,
"intrinsicRotation": 180,
"kind": "stored-comment",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 27,
"intrinsicRotation": 270,
"kind": "stored-comment",
"flags": 8,
"rect": [
42,
48,
74,
64
]
},
{
"page": 28,
"intrinsicRotation": 0,
"kind": "stored-comment",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 29,
"intrinsicRotation": 90,
"kind": "stored-comment",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 30,
"intrinsicRotation": 180,
"kind": "stored-comment",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 31,
"intrinsicRotation": 270,
"kind": "stored-comment",
"flags": 16,
"rect": [
42,
48,
74,
64
]
},
{
"page": 32,
"intrinsicRotation": 0,
"kind": "stored-comment",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 33,
"intrinsicRotation": 90,
"kind": "stored-comment",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 34,
"intrinsicRotation": 180,
"kind": "stored-comment",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 35,
"intrinsicRotation": 270,
"kind": "stored-comment",
"flags": 24,
"rect": [
42,
48,
74,
64
]
},
{
"page": 36,
"intrinsicRotation": 0,
"kind": "visibility-zorder",
"flags": 24
},
{
"page": 37,
"intrinsicRotation": 0,
"kind": "crop-clipping",
"flags": 24,
"rect": [
108,
48,
140,
64
]
}
],
"expected": "At 100% one PDF point is one logical pixel. NoZoom preserves logical 32x16 size across zoom and scales only with DPR. NoRotate preserves upright red-left/blue-right appearance around the original Rect upper-left through intrinsic plus user rotation. Generated red border extends one point beyond Rect. This is synthetic geometry, not a general PDF compatibility golden."
}
@@ -0,0 +1,17 @@
{
"license": "Self-created test content; same license as DocView.",
"sha256": "44879caa880ad8c892e2f0cdca883fe5b8e471a92aecabb5583fb78d3fd34d86",
"originalRect": [
42,
48,
74,
64
],
"nativeIconRect": [
42,
48,
62,
68
],
"expected": "Twelve pages: flags 8/16/24, each with intrinsic rotations 0/90/180/270. Four pages share each annotation. Capture the native generated AP once, retain source Rect, use the captured 20x20 icon Rect for drawing and hit testing."
}
+88
View File
@@ -0,0 +1,88 @@
%PDF-1.7
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 12 /Kids [6 0 R 7 0 R 8 0 R 9 0 R 11 0 R 12 0 R 13 0 R 14 0 R 16 0 R 17 0 R 18 0 R 19 0 R] >>
endobj
3 0 obj
<< /Length 68 >>
stream
BT /F1 10 Tf 12 100 Td (Native icon with unembedded body text) Tj ET
endstream
endobj
4 0 obj
<< /Type /Annot /Subtype /Ink /Rect [80 24 100 34] /F 8 /Contents (Native ink) /BS << /W 4 >> /InkList [[80 24 90 34 100 24]] >>
endobj
5 0 obj
<< /Type /Annot /Subtype /Text /Rect [42 48 74 64] /F 8 /Contents (Native text icon) /C [1 0 0] >>
endobj
6 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [5 0 R 4 0 R 4 0 R] >>
endobj
7 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [5 0 R 4 0 R 4 0 R] >>
endobj
8 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [5 0 R 4 0 R 4 0 R] >>
endobj
9 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [5 0 R 4 0 R 4 0 R] >>
endobj
10 0 obj
<< /Type /Annot /Subtype /Text /Rect [42 48 74 64] /F 16 /Contents (Native text icon) /C [1 0 0] >>
endobj
11 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [10 0 R 4 0 R 4 0 R] >>
endobj
12 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [10 0 R 4 0 R 4 0 R] >>
endobj
13 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [10 0 R 4 0 R 4 0 R] >>
endobj
14 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [10 0 R 4 0 R 4 0 R] >>
endobj
15 0 obj
<< /Type /Annot /Subtype /Text /Rect [42 48 74 64] /F 24 /Contents (Native text icon) /C [1 0 0] >>
endobj
16 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 0 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [15 0 R 4 0 R 4 0 R] >>
endobj
17 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 90 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [15 0 R 4 0 R 4 0 R] >>
endobj
18 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 180 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [15 0 R 4 0 R 4 0 R] >>
endobj
19 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate 270 /Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [15 0 R 4 0 R 4 0 R] >>
endobj
xref
0 20
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000190 00000 n
0000000308 00000 n
0000000452 00000 n
0000000566 00000 n
0000000805 00000 n
0000001045 00000 n
0000001286 00000 n
0000001527 00000 n
0000001643 00000 n
0000001884 00000 n
0000002126 00000 n
0000002369 00000 n
0000002612 00000 n
0000002728 00000 n
0000002969 00000 n
0000003211 00000 n
0000003454 00000 n
trailer
<< /Size 20 /Root 1 0 R >>
startxref
3697
%%EOF
+5
View File
@@ -0,0 +1,5 @@
# CMYK ICC CLUT試験資料
`icc-cmyk-lut.pdf`は、同じCMYK入力をICCベクター・ICC画像・DeviceCMYK対照で表示する生成資料である。自作ICC入力プロファイルのCLUT頂点と数式から色の期待値を定める。制作条件・数値・既知の差は[描画比較記録](../../../results/cmyk-lut/README.md)を参照する。
`manifest.json`はPDFとICCのSHA-256、16個のICC色測定点、8個の対照点、生成器hash、測定対象外の範囲を保持する。物理的な印刷条件やモニターを校正するためのプロファイルではない。PDFiumと期待色の差が見つかっており、正解画像の人による承認は未完了である。
Binary file not shown.
+535
View File
@@ -0,0 +1,535 @@
{
"file": "icc-cmyk-lut.pdf",
"sha256": "3cc5ea798bc61b0d1af2fc1ee256bedc961ca40b05ad2002a9fee6a9227330fe",
"profileFile": "synthetic-cmyk-lab.icc",
"profileSha256": "1708392182ecb3819bb0e4bd1139677be24c9884fff84ad3bb91af5dd42b78f7",
"profileBytes": 588,
"pageSizePt": [
720,
420
],
"profile": {
"version": "2.1",
"class": "scnr",
"input": "CMYK",
"pcs": "Lab ",
"tag": "A2B0",
"type": "mft2",
"gridPointsPerChannel": 2,
"mapping": [
"L=100-12*C-15*M-10*Y-35*K",
"a=18*M-15*C",
"b=20*Y-12*C"
],
"labEncoding": "ICC v2 L: 0..65280 for 0..100; a/b: (value+128)*256",
"source": "Self-authored binary ICC input profile; no borrowed ICC profile"
},
"probes": [
{
"kind": "icc-vector",
"sample": 0,
"pointPt": [
71,
292
],
"components": [
0,
0,
0,
0
],
"lab": [
100,
0,
0
],
"expectedRgb": [
255,
255,
255
]
},
{
"kind": "icc-image",
"sample": 0,
"pointPt": [
76.5,
194
],
"components": [
0.0,
0.0,
0.0,
0.0
],
"lab": [
100.0,
0.0,
0.0
],
"expectedRgb": [
255,
255,
255
]
},
{
"kind": "device-control",
"sample": 0,
"pointPt": [
71,
96
],
"components": [
0,
0,
0,
0
]
},
{
"kind": "icc-vector",
"sample": 1,
"pointPt": [
152,
292
],
"components": [
1,
0,
0,
0
],
"lab": [
88,
-15,
-12
],
"expectedRgb": [
178,
230,
243
]
},
{
"kind": "icc-image",
"sample": 1,
"pointPt": [
157.5,
194
],
"components": [
1.0,
0.0,
0.0,
0.0
],
"lab": [
88.0,
-15.0,
-12.0
],
"expectedRgb": [
178,
230,
243
]
},
{
"kind": "device-control",
"sample": 1,
"pointPt": [
152,
96
],
"components": [
1,
0,
0,
0
]
},
{
"kind": "icc-vector",
"sample": 2,
"pointPt": [
233,
292
],
"components": [
0,
1,
0,
0
],
"lab": [
85,
18,
0
],
"expectedRgb": [
246,
200,
213
]
},
{
"kind": "icc-image",
"sample": 2,
"pointPt": [
238.5,
194
],
"components": [
0.0,
1.0,
0.0,
0.0
],
"lab": [
85.0,
18.0,
0.0
],
"expectedRgb": [
246,
200,
213
]
},
{
"kind": "device-control",
"sample": 2,
"pointPt": [
233,
96
],
"components": [
0,
1,
0,
0
]
},
{
"kind": "icc-vector",
"sample": 3,
"pointPt": [
314,
292
],
"components": [
0,
0,
1,
0
],
"lab": [
90,
0,
20
],
"expectedRgb": [
238,
226,
188
]
},
{
"kind": "icc-image",
"sample": 3,
"pointPt": [
319.5,
194
],
"components": [
0.0,
0.0,
1.0,
0.0
],
"lab": [
90.0,
0.0,
20.0
],
"expectedRgb": [
238,
226,
188
]
},
{
"kind": "device-control",
"sample": 3,
"pointPt": [
314,
96
],
"components": [
0,
0,
1,
0
]
},
{
"kind": "icc-vector",
"sample": 4,
"pointPt": [
395,
292
],
"components": [
0,
0,
0,
1
],
"lab": [
65,
0,
0
],
"expectedRgb": [
158,
158,
158
]
},
{
"kind": "icc-image",
"sample": 4,
"pointPt": [
400.5,
194
],
"components": [
0.0,
0.0,
0.0,
1.0
],
"lab": [
65.0,
0.0,
0.0
],
"expectedRgb": [
158,
158,
158
]
},
{
"kind": "device-control",
"sample": 4,
"pointPt": [
395,
96
],
"components": [
0,
0,
0,
1
]
},
{
"kind": "icc-vector",
"sample": 5,
"pointPt": [
476,
292
],
"components": [
0.25,
0.5,
0.75,
0.2
],
"lab": [
75.0,
5.25,
12.0
],
"expectedRgb": [
201,
181,
163
]
},
{
"kind": "icc-image",
"sample": 5,
"pointPt": [
481.5,
194
],
"components": [
0.25098039215686274,
0.5019607843137255,
0.7490196078431373,
0.2
],
"lab": [
74.96862745098039,
5.270588235294118,
11.968627450980392
],
"expectedRgb": [
201,
181,
163
]
},
{
"kind": "device-control",
"sample": 5,
"pointPt": [
476,
96
],
"components": [
0.25,
0.5,
0.75,
0.2
]
},
{
"kind": "icc-vector",
"sample": 6,
"pointPt": [
557,
292
],
"components": [
0.6,
0.2,
0.4,
0.1
],
"lab": [
82.3,
-5.4,
0.8000000000000007
],
"expectedRgb": [
195,
208,
203
]
},
{
"kind": "icc-image",
"sample": 6,
"pointPt": [
562.5,
194
],
"components": [
0.6,
0.2,
0.4,
0.10196078431372549
],
"lab": [
82.23137254901961,
-5.4,
0.8000000000000007
],
"expectedRgb": [
194,
208,
203
]
},
{
"kind": "device-control",
"sample": 6,
"pointPt": [
557,
96
],
"components": [
0.6,
0.2,
0.4,
0.1
]
},
{
"kind": "icc-vector",
"sample": 7,
"pointPt": [
638,
292
],
"components": [
1,
1,
1,
1
],
"lab": [
28,
3,
8
],
"expectedRgb": [
74,
64,
54
]
},
{
"kind": "icc-image",
"sample": 7,
"pointPt": [
643.5,
194
],
"components": [
1.0,
1.0,
1.0,
1.0
],
"lab": [
28.0,
3.0,
8.0
],
"expectedRgb": [
74,
64,
54
]
},
{
"kind": "device-control",
"sample": 7,
"pointPt": [
638,
96
],
"components": [
1,
1,
1,
1
]
}
],
"tolerance8Bit": 4,
"references": [
"https://archive.color.org/files/icc32.pdf",
"https://www.color.org/chardata/rgb/srgb.xalter"
],
"limits": [
"Synthetic CMYK input CLUT; not a measured print profile or calibrated press proof.",
"No human-approved golden; no physical display or Windows validation."
],
"generatorSha256": "ed93e85cdf4e398409d49bbf941abfe79062c5a35bde359d75f14e4a8746c8f8"
}
Binary file not shown.
+30
View File
@@ -0,0 +1,30 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Kids [3 0 R] /Count 1 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 240 260] /CropBox [20 30 220 230] /Annots [4 0 R 5 0 R] /Resources << >> >>
endobj
4 0 obj
<< /Type /Annot /Subtype /Text /Rect [100 100 120 120] /Contents (<b>Literal comment</b>) /F 4 >>
endobj
5 0 obj
<< /Type /Annot /Subtype /Text /Rect [1000 1000 1020 1020] /Contents (Outside CropBox comment) /F 4 >>
endobj
xref
0 6
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000121 00000 n
0000000256 00000 n
0000000369 00000 n
trailer
<< /Size 6 /Root 1 0 R >>
startxref
487
%%EOF
+2
View File
@@ -0,0 +1,2 @@
%PDF-1.7
This is deliberately corrupt.
+93
View File
@@ -0,0 +1,93 @@
Copyright 2022 The BIZ UDGothic Project Authors (https://github.com/googlefonts/morisawa-biz-ud-mincho)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2023 Marti Maria Saguer
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject
to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+73
View File
@@ -0,0 +1,73 @@
# Extended synthetic PDF corpus
These five original documents contain nine pages. Their drawing source and
explicit expected geometry are in `../extended_generator.py` and `manifest.json`.
They are reproducible test fixtures, not approved golden images.
| Document | Pages | Covered content |
| --- | ---: | --- |
| japanese-layout.pdf | 2 | Embedded Japanese TrueType subset, horizontal text, explicit ruby coordinates, vertical glyph positions, text matrices at 0/90/180/270 degrees |
| graphics-compositing.pdf | 1 | Original RGB and RGBA images, soft mask, 50% vector transparency and overlap, circular clipping, axial shading, CMYK swatches |
| page-geometry.pdf | 4 | Different MediaBox dimensions, offset CropBox, Rotate values 0/90/270/180, four known color markers per page |
| unembedded-font.pdf | 1 | Standard-14 Helvetica, Times-Roman and Courier substitution baseline |
| icc-linear-rgb.pdf | 1 | Embedded linear-sRGB matrix/TRC profile in ICCBased vector and raster colors, plus identical DeviceRGB control values |
The Japanese text uses BIZ UDPGothic Regular. The font is subset-embedded, and
its SIL Open Font License 1.1 is included in `FONT-OFL.txt`. The font file hash
and upstream license URL are recorded in the manifest. The full font file is
not redistributed here. The license permits embedding and redistribution;
these documents do not modify the original font's reserved name.
Generate with Python containing ReportLab, pypdf and Pillow:
```sh
python3 tests/fixtures/pdf/extended_generator.py
```
The default font location is
`/usr/local/share/fonts/BIZ_UDPGothic/BIZUDPGothic-Regular.ttf`.
Set `DOCVIEW_JAPANESE_FONT` to another installation of that font with its adjacent
`OFL.txt` when necessary. A changed font file changes the fixture hashes.
After building DocView's `pdf-worker-evidence` target and installing Poppler command-line tools:
```sh
python3 tests/compare_pdf_extended.py
```
The comparison generates full-resolution PNGs, difference images, contact sheets,
text extraction and a machine-readable report under `tests/results/pdf-extended`.
It assembles pages from the production sandboxed PDF worker's 512-pixel tiles, using FontBroker for unembedded fonts, and
compares them with independently rendered Poppler pages at 144 dpi. CropBox and
Rotate are honored. Deterministic size, marker, alpha and Japanese text/search
assertion failures produce a nonzero exit status; image-difference metrics do
not have an invented acceptance threshold.
The script defaults to system `/usr/bin` Poppler tools when present. Override
with `DOCVIEW_PDFTOPPM`, `DOCVIEW_PDFTOTEXT` and `DOCVIEW_PDFFONTS`, or choose a
different build directory with `DOCVIEW_BUILD_DIR`.
Explicit limitations: vertical text uses individual positioned glyphs, not native
vertical CID metrics or OpenType shaping; ruby positions are authored directly;
CMYK has no calibrated ICC golden; unembedded font coverage is Standard-14 Latin
only. This corpus does not establish arbitrary-document, Windows, accessibility,
print-production or full PDF compatibility.
## ICC profile and additional scale checks
`../icc_generator.py` creates `linear-srgb.icc` from D65 white, sRGB primaries
and gamma 1 through public LittleCMS APIs. It uses no downloaded or borrowed
profile. The generated copyright tag reads `No copyright, use freely`; the
LittleCMS MIT license is retained in `LCMS2-LICENSE.txt`. The manifest records
the numeric parameters, profile hash, library version and upstream source.
The profile's creation timestamp is fixed, and its optional ID is zero, for
reproducibility. The same profile bytes are embedded for vector and image colors.
Run `python3 tests/fixtures/pdf/icc_generator.py` to add/rebuild only this fixture
without requiring the Japanese font. The full generator includes it as well.
`python3 tests/compare_pdf_icc.py` compares actual worker scales 0.5, 1 and 4
against Poppler at 36/72/288 dpi. It checks 54 analytic color probes, page
dimensions and original SHA-256. Linear 0.5 gray must differ materially from
DeviceRGB 0.5; this prevents an ignored ICC profile from passing. Evidence is
in [pdf-icc](../../../results/pdf-icc/README.md). This one RGB profile does not
establish arbitrary ICC LUT, CMYK press calibration or print color proofing.
+129
View File
@@ -0,0 +1,129 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 96 /Length 770 /Subtype /Image
/Type /XObject /Width 96
>>
stream
Gb"/eb=uP&&-Zt`KLJ3YaD-k^$T89A5Q*ko]2*2nDdV>'nltbXI%?Vu\)%#XpZc)FkL,m`a/Lag29tgj>b@o:a%[iE"`irt\m?N"80mR+Ed!;h]g0ju;$/J51FMJH"`f>cfB4U(aX0pU!]d5J6=)+$IGNFNg)],T'?PNNS4Fhm09G3@'(l;dFs:3FOCKQ!p&[7d7-\)$B:5]L(W`!Xp$`#C6_`o<']`d<WH`ua<$EKhe@!'NY)[)LO)]c.jLd`Q,a"f;aDhlMH@[%tOffMA0bR')JXg!iFYAi_9[picjNNI,G_)A.dIhblEjCO$]Kf4A;)PO5hf;f=C2\Ei'20\7"`bfD'YQblRn2$:jOf<2]g.U?8D4I4lk6:EJXg;G#$rEb:=R/hj:$mJcVoph9r-bPE`.`hHIZ`nY)_&hoK4Lg8BqV(6kUqpJK-V2W#*O['Bsgo*$^TQ(Wb8U;YL5Qb<ufP5gGmuLDS#L&m_--+=EXL`=(b&&lJ67E=[*FeZmhtT'$4iaa&H-80UJUOQ.Z#o`@-s,$cj`@jI62!]dk\l<YTGRAbZQaI*_7n,bU;U?hCbjCAq'G_)AaU<#G`mQllF3f867S7!O$09?i=V!%u&gdIlC+NI6QlNM<f7+,BaB9u0F$fiiP2=LZ-F.s^^+D45eI@c%\Ca'TIORn6WdIin<F55;Ce-k=?'?PNNS4Fhm09G3@'(l;dFs:3FOCKQ!p&[7d7-\)$B:5]L(W`!Xp$`#C6_`o<']f2\j)Vm2Hie*:#NP~>endstream
endobj
4 0 obj
<<
/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 96 /Length 436 /SMask 5 0 R
/Subtype /Image /Type /XObject /Width 96
>>
stream
Gb"0NYn=i,&4BAFTbT>?TQUB/+^bKugVU8h=46!:!d7piQ]!T<ba@#L;0$d'Ft!Q^NU%.AnXrWd)$$\)9Qs*b9G^=29X59@P"^O-`"M#1a\)?tA0QDA1(c].R0]FQ9S<pM-GlZ,'B,^LM=<Oa7/3'Y++-U7&O%A+#VR8pKJu^#_/"f>iLQ0\nA=-PGhZaN]P9D<hG^&j';qE-Dl?J&e_j^$cS9;rOZrX*UCZ@jq:kFFD1%Y*o[-/NIItoWTB+Hk++<e/-hI'-C_G^=gA!5XkbF2&T[+mmiZli3N^!;=qTMW4JtnAjPs07%Q/h'Q;'h5d&lmrT,>fc4n3lq/!tu]/UX+T]a5RLsF9^#E7-EM;5]enZf0jIp3[JNtdiD;4S;rCRS9uV$jqjO3)<VYQ,T5baAP/[j8X(Z_/;95JY6\U]b]s:>Ed)6~>endstream
endobj
5 0 obj
<<
/BitsPerComponent 8 /ColorSpace /DeviceGray /Decode [ 0 1 ] /Filter [ /ASCII85Decode /FlateDecode ] /Height 96 /Length 304
/Subtype /Image /Type /XObject /Width 96
>>
stream
Gb"0S5n\f8#Xm(NrrM7A3Eqf<"D;E3/dhbS([pfDKe[mgbWLrJAk+Im:1B'X'+R0&E9b7@TLT>3Ns8u5$3YIH&ELNU0^fApGY]I$mfQ.1(J+/`!.eJ\./Y83p.>0^JB$=E,&[\(5*\&.@\:mE"N3KprsBJ7"oLl`\:6Vfji7Y6J#be&rbT@Jp=m@8YPs!"OADF@%?0KFe\BGlIeE`Qo)I>'pD`]%O*lFWI_R8fJ'.Mpo)5nBIkKXYbO68<qhtB$'Is00,_5FUq]f,IkWg;i3su@CT?-$8":$k1>l'NE%CWPaTE~>endstream
endobj
6 0 obj
<<
/ColorSpace /DeviceRGB /Coords [ 40 205 525 205 ] /Extend [true true] /Function 10 0 R /ShadingType 2
>>
endobj
7 0 obj
<<
/Contents 12 0 R /MediaBox [ 0 0 600 760 ] /Parent 11 0 R /Resources <<
/ExtGState <<
/gRLs0 <<
/ca .5
>> /gRLs1 <<
/ca 1
>>
>> /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /Shading <<
/Sh0 6 0 R
>> /XObject <<
/FormXob.dde330c7bd98d143ad6dbfc31b4d18ea 4 0 R /FormXob.fd3160a8deaece01bd46d36268643177 3 0 R
>>
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
8 0 obj
<<
/PageMode /UseNone /Pages 11 0 R /Type /Catalog
>>
endobj
9 0 obj
<<
/Author (DocView tests) /CreationDate (D:20000101000000+00'00') /Creator (anonymous) /Keywords () /ModDate (D:20000101000000+00'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (unspecified) /Title (DocView synthetic rendering fixture - graphics-compositing.pdf) /Trapped /False
>>
endobj
10 0 obj
<<
/Bounds [ .5 ] /Domain [0.0 1.0] /Encode [ 0 1 0 1 ] /FunctionType 3 /Functions [ 13 0 R 14 0 R ]
>>
endobj
11 0 obj
<<
/Count 1 /Kids [ 7 0 R ] /Type /Pages
>>
endobj
12 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 845
>>
stream
Gatm9gMY_1&:O:SbY+cjMTjqjIO$ibPuJGK[=):r@q`ZT`bP;HbjJqLW1m*#!M8t1B$NEC1PPtI%s?KG"`T_lmu@H\ON`64:d?dhgE['(L^A]q;5poh)[T*0/qPu(Z2opN")sn#EcVO!UQDS8o>>'fE'&UloS94=52,>]_eA]3D1KgOIK.<jXri.Ar;t)Z81n_Y562M9k<^[)81'F7d(?@De^%tKc8&-00fmKPT&t]$1SHS,(buhr7M4ET_>![M:oB_:lsC&7PXm/F<j2b?N!EFg=ICAJKY1QY]#Z\#U"jgILY>%I0p,WaEm/!DPsrb,3;#>6,l=W`QsC\'D10!!ZRk:0UsV#WF[cNnREDD5PgcVQW6WZ`=rlm'/;ie@Q12G"k-1gs%BRe9WN.d$YpNp508tV'*A8'6LNJ)%b`$tS=6Zs9UK<D0)Zmt_IAI'!,fK-:4[#RkO'9;9"@Y;Q,Z(9U[4u<d1ah"6:S'*3S#8t\A*1-QA[0H<?lH,l-SWa:g`/."MNrEuaF3/NJs29(`BZ,f>K@YR'5(5`$P=l1[GPT]28J)$4K2]0f_b%<32\Bi[HVIQHg<)e!A0oXIU#-PbH?\gWNAePNr&b\l)b#J#=06oCCm"4KA_D$"=M\A32$PmjQrjZ)e3\B9j[;N,$chPCRk@#!X%\]:7(cr>@@J@K*j12).Jf@e*'Ng"?,lCgQcM<X8VG&/7EXALKR?[.#Z89DAI_;)6=dERPO35o[sL4H+&iU';_GZ7(l6T3.c(]2jIlchs'>q8-cU%j0>gfM%@P4ft+tP*W^V$$d?!W5[^)K!#UiZJ?>:k1rb#QV/c)<R*Z<s"><Zd_&3~>endstream
endobj
13 0 obj
<<
/C0 [ .078431 .490196 .47451 ] /C1 [ 1 1 1 ] /Domain [ 0 1 ] /FunctionType 2 /N 1
>>
endobj
14 0 obj
<<
/C0 [ 1 1 1 ] /C1 [ .85098 .313725 .313725 ] /Domain [ 0 1 ] /FunctionType 2 /N 1
>>
endobj
xref
0 15
0000000000 65535 f
0000000061 00000 n
0000000092 00000 n
0000000199 00000 n
0000001157 00000 n
0000001794 00000 n
0000002303 00000 n
0000002426 00000 n
0000002814 00000 n
0000002883 00000 n
0000003202 00000 n
0000003322 00000 n
0000003382 00000 n
0000004318 00000 n
0000004422 00000 n
trailer
<<
/ID
[<998c181bcc6a27b405fdaeda1882afd9><998c181bcc6a27b405fdaeda1882afd9>]
% ReportLab generated PDF document -- digest (opensource)
/Info 9 0 R
/Root 8 0 R
/Size 15
>>
startxref
4526
%%EOF
Binary file not shown.
Binary file not shown.
Binary file not shown.
+776
View File
@@ -0,0 +1,776 @@
{
"origin": "Original deterministic vector, text and raster drawings authored for DocView tests",
"reference_status": "Synthetic source specifies content and coordinates; no human-approved golden image exists",
"font": {
"family": "BIZ UDPGothic Regular",
"source_file": "BIZUDPGothic-Regular.ttf",
"sha256": "22f41ce68f1ce62477ca4ec1e2c0c400cc545ddff31d713e8edf87808614aeb2",
"license": "SIL Open Font License 1.1",
"license_copy": "FONT-OFL.txt",
"upstream": "https://github.com/googlefonts/morisawa-biz-ud-gothic",
"upstream_license": "https://raw.githubusercontent.com/googlefonts/morisawa-biz-ud-gothic/main/OFL.txt",
"embedding": "Subset embedded by ReportLab; OFL permits embedding and redistribution. No reserved font name is changed."
},
"documents": [
{
"file": "japanese-layout.pdf",
"sha256": "47011b3c7c7363bc9549881ade31b836e1efdae555504076627978dbde136f00",
"page_count": 2,
"expected": {
"page_sizes_pt": [
[
540,
720
],
[
540,
720
]
],
"horizontal_text": "日本語の文字配置と埋込みフォント",
"vertical_columns": [
{
"x": 420,
"top": 590,
"step": 32,
"text": "日本語縦書き検証"
},
{
"x": 374,
"top": 590,
"step": 32,
"text": "天地左右回転配置"
}
],
"text_matrix_rotations_degrees": [
0,
90,
180,
270
],
"font_embedded": true
},
"limits": [
"Manual vertical glyph placement does not test native vertical CID metrics or OpenType shaping.",
"Ruby placement is explicit source geometry, not automatic ruby layout."
]
},
{
"file": "graphics-compositing.pdf",
"sha256": "ddaec9f619dde57995e9baff6a560151e9757d4b1bdce9b630299a5f0438d49e",
"page_count": 1,
"expected": {
"page_sizes_pt": [
[
600,
760
]
],
"rgb_image_pixels": [
96,
96
],
"alpha": 0.5,
"alpha_probes": [
{
"point_pt": [
80,
370
],
"expected_rgb": [
244,
119,
121
],
"region": "red over gray"
},
{
"point_pt": [
180,
390
],
"expected_rgb": [
116,
119,
248
],
"region": "blue over gray"
},
{
"point_pt": [
130,
390
],
"expected_rgb": [
122,
59,
188
],
"region": "blue over red over gray"
}
],
"clip_circle_pt": [
390,
395,
64
],
"axial_shading_band_pt": [
40,
205,
485,
62
],
"cmyk_swatches": [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
]
},
"limits": [
"CMYK output depends on renderer color conversion; no approved ICC reference is supplied.",
"Pixel differences are evidence, not a calibrated quality threshold."
]
},
{
"file": "page-geometry.pdf",
"sha256": "e5c0e4cb6d73c322235c9d7c89cf1e2e925ac7d3c22c7672b595a193fa133a0f",
"page_count": 4,
"expected": {
"pages": [
{
"media_box_pt": [
0,
0,
420,
320
],
"crop_box_pt": [
30,
40,
390,
300
],
"rotation": 0,
"display_size_pt": [
360,
260
],
"markers_pdf_coordinates": [
{
"x": 50,
"y": 60,
"rgb": [
255,
0,
0
]
},
{
"x": 370,
"y": 60,
"rgb": [
0,
170,
0
]
},
{
"x": 370,
"y": 280,
"rgb": [
0,
0,
255
]
},
{
"x": 50,
"y": 280,
"rgb": [
255,
170,
0
]
}
]
},
{
"media_box_pt": [
0,
0,
560,
360
],
"crop_box_pt": [
20,
30,
520,
330
],
"rotation": 90,
"display_size_pt": [
300,
500
],
"markers_pdf_coordinates": [
{
"x": 40,
"y": 50,
"rgb": [
255,
0,
0
]
},
{
"x": 500,
"y": 50,
"rgb": [
0,
170,
0
]
},
{
"x": 500,
"y": 310,
"rgb": [
0,
0,
255
]
},
{
"x": 40,
"y": 310,
"rgb": [
255,
170,
0
]
}
]
},
{
"media_box_pt": [
0,
0,
300,
600
],
"crop_box_pt": [
15,
50,
285,
550
],
"rotation": 270,
"display_size_pt": [
500,
270
],
"markers_pdf_coordinates": [
{
"x": 35,
"y": 70,
"rgb": [
255,
0,
0
]
},
{
"x": 265,
"y": 70,
"rgb": [
0,
170,
0
]
},
{
"x": 265,
"y": 530,
"rgb": [
0,
0,
255
]
},
{
"x": 35,
"y": 530,
"rgb": [
255,
170,
0
]
}
]
},
{
"media_box_pt": [
0,
0,
480,
480
],
"crop_box_pt": [
60,
80,
420,
400
],
"rotation": 180,
"display_size_pt": [
360,
320
],
"markers_pdf_coordinates": [
{
"x": 80,
"y": 100,
"rgb": [
255,
0,
0
]
},
{
"x": 400,
"y": 100,
"rgb": [
0,
170,
0
]
},
{
"x": 400,
"y": 380,
"rgb": [
0,
0,
255
]
},
{
"x": 80,
"y": 380,
"rgb": [
255,
170,
0
]
}
]
}
]
},
"limits": [
"Renderer comparisons must use CropBox and honor document Rotate."
]
},
{
"file": "unembedded-font.pdf",
"sha256": "37532f1b3a403c5527fe39807e2bb737b55472d8edf32cc1ca47668c7623e095",
"page_count": 1,
"expected": {
"page_sizes_pt": [
[
400,
300
]
],
"base_fonts": [
"Helvetica",
"Times-Roman",
"Courier"
],
"font_embedded": false
},
"limits": [
"This is a controlled Standard-14 substitution baseline, not arbitrary missing Japanese font coverage.",
"Cross-OS fallback is not established by this Linux-only comparison."
]
},
{
"file": "icc-linear-rgb.pdf",
"sha256": "4a6fd71d761bb639d3587f39e94446b8b92c6448177bbcc161a622b94aac9a06",
"page_count": 1,
"expected": {
"page_sizes_pt": [
[
600,
350
]
],
"icc_probes": [
{
"kind": "icc-vector",
"point_pt": [
68,
248
],
"components": [
0.0625,
0.0625,
0.0625
],
"expected_rgb": [
71,
71,
71
]
},
{
"kind": "device-control",
"point_pt": [
68,
164
],
"components": [
0.0625,
0.0625,
0.0625
],
"expected_rgb": [
16,
16,
16
]
},
{
"kind": "icc-image",
"point_pt": [
74,
68
],
"components": [
16,
16,
16
],
"expected_rgb": [
71,
71,
71
]
},
{
"kind": "icc-vector",
"point_pt": [
156,
248
],
"components": [
0.25,
0.25,
0.25
],
"expected_rgb": [
137,
137,
137
]
},
{
"kind": "device-control",
"point_pt": [
156,
164
],
"components": [
0.25,
0.25,
0.25
],
"expected_rgb": [
64,
64,
64
]
},
{
"kind": "icc-image",
"point_pt": [
162,
68
],
"components": [
64,
64,
64
],
"expected_rgb": [
137,
137,
137
]
},
{
"kind": "icc-vector",
"point_pt": [
244,
248
],
"components": [
0.5,
0.5,
0.5
],
"expected_rgb": [
188,
188,
188
]
},
{
"kind": "device-control",
"point_pt": [
244,
164
],
"components": [
0.5,
0.5,
0.5
],
"expected_rgb": [
128,
128,
128
]
},
{
"kind": "icc-image",
"point_pt": [
250,
68
],
"components": [
128,
128,
128
],
"expected_rgb": [
188,
188,
188
]
},
{
"kind": "icc-vector",
"point_pt": [
332,
248
],
"components": [
0.75,
0.75,
0.75
],
"expected_rgb": [
225,
225,
225
]
},
{
"kind": "device-control",
"point_pt": [
332,
164
],
"components": [
0.75,
0.75,
0.75
],
"expected_rgb": [
191,
191,
191
]
},
{
"kind": "icc-image",
"point_pt": [
338,
68
],
"components": [
191,
191,
191
],
"expected_rgb": [
224,
224,
224
]
},
{
"kind": "icc-vector",
"point_pt": [
420,
248
],
"components": [
0.5,
0.125,
0.0625
],
"expected_rgb": [
188,
99,
71
]
},
{
"kind": "device-control",
"point_pt": [
420,
164
],
"components": [
0.5,
0.125,
0.0625
],
"expected_rgb": [
128,
32,
16
]
},
{
"kind": "icc-image",
"point_pt": [
426,
68
],
"components": [
128,
32,
16
],
"expected_rgb": [
188,
99,
71
]
},
{
"kind": "icc-vector",
"point_pt": [
508,
248
],
"components": [
0.0625,
0.25,
0.5
],
"expected_rgb": [
71,
137,
188
]
},
{
"kind": "device-control",
"point_pt": [
508,
164
],
"components": [
0.0625,
0.25,
0.5
],
"expected_rgb": [
16,
64,
128
]
},
{
"kind": "icc-image",
"point_pt": [
514,
68
],
"components": [
16,
64,
128
],
"expected_rgb": [
71,
137,
188
]
}
],
"probe_tolerance_rgb": 3,
"profile_effect": "ICCBased 0.5 linear gray becomes approximately 188, distinct from DeviceRGB approximately 128."
},
"limits": [
"One RGB matrix/TRC profile, not arbitrary ICC LUT/CMYK/printing conformance.",
"Analytic sRGB color expectation; independent renderer comparison still requires visual review."
]
}
],
"color_profile": {
"file": "linear-srgb.icc",
"sha256": "343c89fd0eb35fff20bcd52b63d3b3b941702e443c46f0761ab367fcf67c6287",
"bytes": 568,
"source": "Self-created with LittleCMS cmsCreateRGBProfile using the stated numeric white point, primaries and gamma; no third-party ICC profile is copied.",
"lcms_encoded_version": 2190,
"lcms_license": "MIT; LCMS2-LICENSE.txt",
"upstream": "https://github.com/mm2/Little-CMS",
"profile_copyright_tag": "No copyright, use freely",
"white_xy": [
0.3127,
0.329
],
"primaries_xy": [
[
0.64,
0.33
],
[
0.3,
0.6
],
[
0.15,
0.06
]
],
"gamma": 1,
"timestamp_normalization": "Header creation time is fixed to 2026-09-19; optional profile ID is zero."
}
}
+161
View File
@@ -0,0 +1,161 @@
%PDF-1.4
%âãÏÓ
1 0 obj
<<
/Producer (pypdf)
/Title (DocView page geometry fixture)
/Author (DocView tests)
>>
endobj
2 0 obj
<<
/Type /Pages
/Count 4
/Kids [ 4 0 R 8 0 R 10 0 R 12 0 R ]
>>
endobj
3 0 obj
<<
/Type /Catalog
/Pages 2 0 R
>>
endobj
4 0 obj
<<
/Contents 5 0 R
/MediaBox [ 0 0 420 320 ]
/Resources <<
/Font 6 0 R
/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>>
/Rotate 0
/Trans <<
>>
/Type /Page
/CropBox [ 30 40 390 300 ]
/Parent 2 0 R
>>
endobj
5 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ]
/Length 535
>>
stream
Gatn"4\s!M%#4NU$BK^68Y"*G3<UlA#eD/`-j:X<4*2HoT9&@dBnVRMB[t&+?e^X)7Y@F:bLhjUb79QX1h_R1&[ZC,F;JoM2&b1^(8uYL[nk7PdOZk%oPFhX4<Pf^&i:;tOB6rrLR"Z?SWiK*,oWihj!#Uo,e7e>(,!sqM\8OJ#t7@Ci3M=`<]p)8FfgQ_+Km?A>.,0d&R:V9X[CC3Z#<6/p;L/rp$WjYDEU3-Z^Hp5`5i*U&Bcba#mnrQWLu5!`?u$>MMeXZM2#dO@OWkRMD9)r8<rmTW%_gIN%)B'_)MJd>[email protected]?u!2^a7bP37]8'A8n;G_B#qge=&C?,]uBKqVa@/a(/I>ERVJC+IS4*TX^Xbdm:da@5MHaB%&L6>04X+6g8T@%D+O^*6=T85'hQ]K4jpmsou#&b[i<cVMZ("BV)Kh/35#&)B$`#Ft<s"!nEGpBH;n%8O@$\)l`[DN$WPgNEj7_1PXps45:cSM""0(DuVL:TH@3+7D;$+(4m/?U#TdLULq%br61tiJm~>
endstream
endobj
6 0 obj
<<
/F1 7 0 R
>>
endobj
7 0 obj
<<
/BaseFont /Helvetica
/Encoding /WinAnsiEncoding
/Name /F1
/Subtype /Type1
/Type /Font
>>
endobj
8 0 obj
<<
/Contents 9 0 R
/MediaBox [ 0 0 560 360 ]
/Resources <<
/Font 6 0 R
/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>>
/Rotate 90
/Trans <<
>>
/Type /Page
/CropBox [ 20 30 520 330 ]
/Parent 2 0 R
>>
endobj
9 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ]
/Length 540
>>
stream
Gatn"9i'Ou&;KZL(%8Cr.*VHrf/XU7\b(DcDH.3("@Pn+X(;n@r6@uFa/piadR:@\Sp+cfgG+?AAS[&-3:Ck\OhhP+4ZKeLr?kkD%AQY3F1`t#iM"q-=POJ#I"r=.-R.'lS5/4c:"j/;=iejQk[%9+n;P^?3;Gu5\X?SW5nfDLA$TE;34X^(N@6]!4#B.01%EiZaLbHQ2Q>RWA4b/QVt&1F:!'AUC":N%LW6jYNBZ+@(28=UUHjrE?:f7tL)7E]TcnUpT+/jU'k*40B/pC*,dtgPET("BC"[j.nsoM<B<7WCo*hRG7ArS-.09#_1O@2W-%Ock_S8sndqK944N>KmDJ$toTjfUO@SdrMS=^:>7Hu\-Y;fT@fl>?*CM'k>?C+YX[N%>J[uTJqa`$XV+kl)@.h_6,Uud3L/2)2r7W9a3$1G#]>[>5*$oe(Dm;YNan'QVTJ"e+dX?]h&rOp(6XMVqbs7:X<L+eQ^AKdt-ApF1Kh^ZUUde2Yg#H$7n_rD6UbOZ>'7Z;9'e'$Qlf2fl;quZ"8i5G~>
endstream
endobj
10 0 obj
<<
/Contents 11 0 R
/MediaBox [ 0 0 300 600 ]
/Resources <<
/Font 6 0 R
/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>>
/Rotate 270
/Trans <<
>>
/Type /Page
/CropBox [ 15 50 285 550 ]
/Parent 2 0 R
>>
endobj
11 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ]
/Length 546
>>
stream
Gatn"9hu``%#46B.srlR%>b`GfcqW^V$BEO<qQI9JG>MfC:gGBr7]H:7TC`eltGFtZ2HkMN%GlqXH)TMi-^.*Y8/\+oDmI'*i<jp3=QbDjAoq]Zb+7dUM8!j#lNT)n8QU&o&uqs+9NGiS%<GnjlVH\r^]Q[Z@F*L?R6$S5%GEX0R*hm]VoBURkTCtPtC$sag`C^)(F6pZGLjBPrZV1^c#!qBs@[bT1@2120m/E/N2pu#N["Zr*j6T=Q";L'SD]l8eMIPL9.@LlM7@[;FfBV")896Ck]hG43#-7+AFkCV'9":aSD@^b)jes@QQo!;sY-=;&K\Hm"(9Q6]17ZeLeWiU$sJ.rV&!oL%QI%]+om;'t)kiU@tAl[,X8:UL&/a4B+e`j;./FaO0jL5oA!I8Gq.NoV@7H>D0@P;J?^9g<rXld6$FF"hn66?!W&7;n1NKDtgRp_\#Sg0HEg3LD!'&nGa-V;^-4dg\s7k^;CIS-gX%u9JRd_o<XZ8AYn^jbmQ)3]>pfY/8r;tE&Y]4^4(LBTC9fq%#2MW?f@C~>
endstream
endobj
12 0 obj
<<
/Contents 13 0 R
/MediaBox [ 0 0 480 480 ]
/Resources <<
/Font 6 0 R
/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>>
/Rotate 180
/Trans <<
>>
/Type /Page
/CropBox [ 60 80 420 400 ]
/Parent 2 0 R
>>
endobj
13 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ]
/Length 540
>>
stream
Gatn"9lJN8&;KZL(%2a7.eVFh4?6;=HJq\cg^o7(VH&36U1GkOoC7c(euFhAYgIbZPBUW1G[uD_&*^ZA^u^N5%g92*+$dR7Qp9SFmKbtfajO;YiN_-ORcj<-XEZ^_6@&4bBFr'6)J@6/UFE\(;>49?"=CX0iJ9qnWCnd?TOS0DK.Upa%']o8[1ZoI04sIccjrgdWiIJiF`0ZV0bmPc:KC*+Fm3XHM=F0,+dPmfqb_g9&:.7ddk3TPAKs%g'M+RKWZ+b(P`Ql[RYJ-q`1W>lcrs\,%;CC8W$]hVd2Wrna0-X,-V1KOUpr`i'9Z9:>q!:Q&/(hl#1I.jRS\6nP?o=[(KbQWlYlua$Yg]W\=k&T"Z/'+-[!e8-d5NN2!ZXS#-oU@)2mA"0QOf-2Y]QK[p57cY7'O:&u1][eMP&O,N]GRDVeZ+_;bU+qr?LPNH4V+o/Fm+P4R!87U+N[[rA,phB2GU0D@-p4IYm:M<FA/(1Y)V[n`/Kh)t)=A%Ofb54,R;s#T0*MY1QVnU/+.pJ!GcIfP!6j=L~>
endstream
endobj
xref
0 14
0000000000 65535 f
0000000015 00000 n
0000000117 00000 n
0000000196 00000 n
0000000245 00000 n
0000000461 00000 n
0000001087 00000 n
0000001118 00000 n
0000001225 00000 n
0000001442 00000 n
0000002073 00000 n
0000002293 00000 n
0000002931 00000 n
0000003151 00000 n
trailer
<<
/Size 14
/Root 3 0 R
/Info 1 0 R
>>
startxref
3783
%%EOF
+80
View File
@@ -0,0 +1,80 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/Contents 9 0 R /MediaBox [ 0 0 400 300 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/PageMode /UseNone /Pages 8 0 R /Type /Catalog
>>
endobj
7 0 obj
<<
/Author (DocView tests) /CreationDate (D:20000101000000+00'00') /Creator (anonymous) /Keywords () /ModDate (D:20000101000000+00'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (unspecified) /Title (DocView synthetic rendering fixture - unembedded-font.pdf) /Trapped /False
>>
endobj
8 0 obj
<<
/Count 1 /Kids [ 5 0 R ] /Type /Pages
>>
endobj
9 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 419
>>
stream
Gatmt>u/<k'Sc)P($AIhR-Qqe4(+PV0G'+KG@`jgin!'H&H)4PM?tG@1bh^"PG[MghK&tdndnfr%%ouH4<QltTEu0&Z[hbcV_sH9:#,fo+L]a<jR$,/JRVs_Cp6o,A,fiKP!.LJ_6>4<K9L$5%m%Gfq&W4C47q6:%n9k*_(_[_5aOa^IcWU#G@]0>Aa<d9_2:aa"mo(:o7MtXjjeL'&.V2hisD:5hVCCYrh#LdNmb49'Orn*nE!T;M1"u$Pgt*OZJE3G:(5UW*OjEYcmlWso)ad5.Q6B+QM#6h1!tRS="0%]6W$.4b;*QRVHi%6gm"KIgsNjPlajrWo6%mSBH750KPrT"'sF@N?Znl&d+""-L"=;E-5@1K/)n.apHCkLX?b^<OsBL%YVb0ea=G&BL2i0WG)u]=D[(cofD~>endstream
endobj
xref
0 10
0000000000 65535 f
0000000061 00000 n
0000000112 00000 n
0000000219 00000 n
0000000328 00000 n
0000000433 00000 n
0000000626 00000 n
0000000694 00000 n
0000001008 00000 n
0000001067 00000 n
trailer
<<
/ID
[<fc20ccc2e85c965a23d5494cd2381a69><fc20ccc2e85c965a23d5494cd2381a69>]
% ReportLab generated PDF document -- digest (opensource)
/Info 7 0 R
/Root 6 0 R
/Size 10
>>
startxref
1576
%%EOF
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env python3
"""Create deterministic, original PDF fixtures with explicit drawing geometry.
Dependencies: ReportLab, pypdf, Pillow. The Japanese font is subset-embedded;
its adjacent SIL OFL license is copied alongside the generated documents.
"""
from pathlib import Path
from io import BytesIO
import hashlib
import json
import os
import shutil
from PIL import Image, ImageDraw
from pypdf import PdfReader, PdfWriter
from pypdf.generic import NameObject, NumberObject, RectangleObject
from reportlab.lib import colors
from reportlab.lib.utils import ImageReader
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
HERE = Path(__file__).resolve().parent
OUT = HERE / "extended"
FONT = Path(os.environ.get("DOCVIEW_JAPANESE_FONT", "/usr/local/share/fonts/BIZ_UDPGothic/BIZUDPGothic-Regular.ttf"))
LICENSE = FONT.parent / "OFL.txt"
OUT.mkdir(parents=True, exist_ok=True)
if not FONT.is_file() or not LICENSE.is_file():
raise SystemExit("Set DOCVIEW_JAPANESE_FONT to BIZUDPGothic-Regular.ttf with its adjacent OFL.txt.")
license_text = LICENSE.read_text(encoding="utf-8")
if "SIL OPEN FONT LICENSE Version 1.1" not in license_text:
raise SystemExit("The expected SIL Open Font License was not found.")
pdfmetrics.registerFont(TTFont("FixtureJapanese", str(FONT)))
shutil.copyfile(LICENSE, OUT / "FONT-OFL.txt")
manifest = {
"origin": "Original deterministic vector, text and raster drawings authored for DocView tests",
"reference_status": "Synthetic source specifies content and coordinates; no human-approved golden image exists",
"font": {
"family": "BIZ UDPGothic Regular", "source_file": FONT.name,
"sha256": hashlib.sha256(FONT.read_bytes()).hexdigest(),
"license": "SIL Open Font License 1.1", "license_copy": "FONT-OFL.txt",
"upstream": "https://github.com/googlefonts/morisawa-biz-ud-gothic",
"upstream_license": "https://raw.githubusercontent.com/googlefonts/morisawa-biz-ud-gothic/main/OFL.txt",
"embedding": "Subset embedded by ReportLab; OFL permits embedding and redistribution. No reserved font name is changed.",
},
"documents": [],
}
def new_canvas(name, size):
result = canvas.Canvas(str(OUT / name), pagesize=size, invariant=1, pageCompression=1)
result.setTitle("DocView synthetic rendering fixture - " + name)
result.setAuthor("DocView tests")
return result
def label(c, x, y, text, size=11):
c.setFillColor(colors.HexColor("#263746"))
c.setFont("Helvetica", size)
c.drawString(x, y, text)
def japanese(c, x, y, text, size=21):
c.setFillColor(colors.HexColor("#132c35"))
c.setFont("FixtureJapanese", size)
c.drawString(x, y, text)
def record(name, pages, expected, limits):
manifest["documents"].append({"file": name, "sha256": hashlib.sha256((OUT / name).read_bytes()).hexdigest(),
"page_count": pages, "expected": expected, "limits": limits})
c = new_canvas("japanese-layout.pdf", (540, 720))
label(c, 38, 675, "EMBEDDED JAPANESE / HORIZONTAL", 17)
japanese(c, 38, 614, "日本語の文字配置と埋込みフォント", 23)
japanese(c, 38, 557, "漢字・ひらがな・カタカナ・1234", 21)
japanese(c, 38, 500, "読み取り専用の文書表示を検証します。", 20)
label(c, 38, 454, "ASCII text uses the same embedded Japanese font:")
japanese(c, 38, 420, "DocView 0123456789 ABC xyz", 20)
japanese(c, 55, 330, "漢字", 29)
japanese(c, 55, 364, "かんじ", 11)
label(c, 155, 341, "Ruby has explicit, independent PDF coordinates.")
c.setStrokeColor(colors.HexColor("#147d79")); c.setLineWidth(1)
c.rect(38, 220, 464, 76, fill=0)
japanese(c, 53, 262, "天地左右", 23)
label(c, 53, 236, "Four ideographs above must remain distinct and correctly placed.")
label(c, 38, 55, "540 x 720 pt / exact source coordinates / embedded TrueType subset")
c.showPage()
label(c, 38, 675, "EMBEDDED JAPANESE / EXPLICIT VERTICAL POSITIONS", 15)
columns = [{"x": 420, "top": 590, "step": 32, "text": "日本語縦書き検証"},
{"x": 374, "top": 590, "step": 32, "text": "天地左右回転配置"}]
for col in columns:
for index, glyph in enumerate(col["text"]):
japanese(c, col["x"], col["top"] - index * col["step"], glyph, 24)
c.setStrokeColor(colors.HexColor("#d7e8e6")); c.line(col["x"] - 5, 315, col["x"] - 5, 620)
for x, y, angle in [(80, 525, 0), (230, 485, 90), (200, 310, 180), (65, 350, 270)]:
c.saveState(); c.translate(x, y); c.rotate(angle); japanese(c, 0, 0, "天地左右", 20); c.restoreState()
label(c, 38, 228, "Right column is read top to bottom; the next column is to its left.")
label(c, 38, 205, "Four lower-left samples use text matrices at 0 / 90 / 180 / 270 degrees.")
label(c, 38, 73, "This tests explicit glyph placement, not vertical CID metrics or shaping.")
label(c, 38, 55, "540 x 720 pt / each glyph has a documented baseline")
c.save()
record("japanese-layout.pdf", 2,
{"page_sizes_pt": [[540, 720], [540, 720]], "horizontal_text": "日本語の文字配置と埋込みフォント",
"vertical_columns": columns, "text_matrix_rotations_degrees": [0, 90, 180, 270], "font_embedded": True},
["Manual vertical glyph placement does not test native vertical CID metrics or OpenType shaping.", "Ruby placement is explicit source geometry, not automatic ruby layout."])
c = new_canvas("graphics-compositing.pdf", (600, 760))
label(c, 35, 721, "IMAGES / ALPHA / CLIPPING / SHADING / CMYK", 17)
image = Image.new("RGB", (96, 96), "white"); drawing = ImageDraw.Draw(image)
for y in range(0, 96, 12):
for x in range(0, 96, 12): drawing.rectangle((x, y, x + 11, y + 11), fill="#147d79" if (x + y) // 12 % 2 == 0 else "#e9b44c")
drawing.line((0, 0, 95, 95), fill="black", width=4)
c.drawImage(ImageReader(image), 40, 524, width=144, height=144)
label(c, 40, 505, "96 x 96 RGB image, enlarged 1.5x")
alpha = Image.new("RGBA", (96, 96), (0, 0, 0, 0)); d = ImageDraw.Draw(alpha)
d.ellipse((4, 4, 92, 92), fill=(224, 63, 90, 150)); d.rectangle((15, 37, 81, 58), fill=(30, 70, 220, 190))
c.setFillColor(colors.HexColor("#dfe7ed")); c.rect(310, 524, 144, 144, stroke=0, fill=1)
c.drawImage(ImageReader(alpha), 310, 524, width=144, height=144, mask="auto")
label(c, 310, 505, "RGBA image with soft mask")
c.setFillColor(colors.HexColor("#e8edf1")); c.rect(40, 330, 220, 135, fill=1, stroke=0)
c.saveState(); c.setFillColor(colors.red); c.setFillAlpha(0.5); c.rect(55, 345, 95, 95, fill=1, stroke=0)
c.setFillColor(colors.blue); c.setFillAlpha(0.5); c.rect(112, 365, 105, 75, fill=1, stroke=0); c.restoreState()
label(c, 40, 308, "Two vector rectangles at 50% alpha")
c.saveState(); path = c.beginPath(); path.circle(390, 395, 64); c.clipPath(path, stroke=0, fill=0)
c.drawImage(ImageReader(image), 300, 310, width=180, height=180); c.restoreState()
c.setStrokeColor(colors.HexColor("#263746")); c.circle(390, 395, 64, fill=0, stroke=1)
label(c, 310, 308, "Raster image clipped to a circle")
c.saveState(); path = c.beginPath(); path.rect(40, 205, 485, 62); c.clipPath(path, stroke=0, fill=0)
c.linearGradient(40, 205, 525, 205, [colors.HexColor("#147d79"), colors.white, colors.HexColor("#d95050")], [0, 0.5, 1]); c.restoreState()
label(c, 40, 185, "Axial PDF shading, clipped to a 485 x 62 pt band")
swatches = [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)]
for index, value in enumerate(swatches):
c.setFillColorCMYK(*value); c.rect(40 + index * 124, 76, 105, 67, stroke=0, fill=1)
label(c, 40 + index * 124, 56, "CMYK " + "".join(map(str, value)), 10)
c.save()
record("graphics-compositing.pdf", 1, {"page_sizes_pt": [[600, 760]], "rgb_image_pixels": [96, 96],
"alpha": 0.5, "alpha_probes": [
{"point_pt": [80, 370], "expected_rgb": [244, 119, 121], "region": "red over gray"},
{"point_pt": [180, 390], "expected_rgb": [116, 119, 248], "region": "blue over gray"},
{"point_pt": [130, 390], "expected_rgb": [122, 59, 188], "region": "blue over red over gray"}],
"clip_circle_pt": [390, 395, 64], "axial_shading_band_pt": [40, 205, 485, 62], "cmyk_swatches": swatches},
["CMYK output depends on renderer color conversion; no approved ICC reference is supplied.", "Pixel differences are evidence, not a calibrated quality threshold."])
geometries = [([420, 320], [30, 40, 390, 300], 0), ([560, 360], [20, 30, 520, 330], 90),
([300, 600], [15, 50, 285, 550], 270), ([480, 480], [60, 80, 420, 400], 180)]
geometry_buffer = BytesIO(); c = canvas.Canvas(geometry_buffer, invariant=1, pageCompression=1)
expectations = []
for number, (size, crop, rotation) in enumerate(geometries, 1):
c.setPageSize(size)
left, bottom, right, top = crop; width, height = right - left, top - bottom
c.setFillColor(colors.HexColor("#ffd6d6")); c.rect(0, 0, *size, fill=1, stroke=0)
c.setFillColor(colors.white); c.rect(left, bottom, width, height, fill=1, stroke=0)
c.setStrokeColor(colors.black); c.setLineWidth(1); c.rect(left + 1, bottom + 1, width - 2, height - 2, fill=0)
dots = [(left + 20, bottom + 20, [255, 0, 0]), (right - 20, bottom + 20, [0, 170, 0]),
(right - 20, top - 20, [0, 0, 255]), (left + 20, top - 20, [255, 170, 0])]
for x, y, rgb in dots:
c.setFillColor(colors.Color(*(v / 255 for v in rgb))); c.circle(x, y, 8, fill=1, stroke=0)
label(c, left + 35, bottom + height * 0.55, f"PAGE {number} / Rotate {rotation}", 15)
label(c, left + 35, bottom + height * 0.55 - 25, f"CropBox {crop}", 10)
label(c, left + 35, bottom + height * 0.55 - 45, "Pink margin must be excluded.", 10)
expectations.append({"media_box_pt": [0, 0, *size], "crop_box_pt": crop, "rotation": rotation,
"display_size_pt": [height, width] if rotation % 180 else [width, height],
"markers_pdf_coordinates": [{"x": x, "y": y, "rgb": rgb} for x, y, rgb in dots]})
c.showPage()
c.save(); source = PdfReader(BytesIO(geometry_buffer.getvalue())); writer = PdfWriter()
for page, (_, crop, rotation) in zip(source.pages, geometries):
page.cropbox = RectangleObject(crop); page[NameObject("/Rotate")] = NumberObject(rotation); writer.add_page(page)
writer.add_metadata({"/Title": "DocView page geometry fixture", "/Author": "DocView tests"})
with (OUT / "page-geometry.pdf").open("wb") as output: writer.write(output)
record("page-geometry.pdf", 4, {"pages": expectations}, ["Renderer comparisons must use CropBox and honor document Rotate."])
c = new_canvas("unembedded-font.pdf", (400, 300))
label(c, 30, 252, "UNEMBEDDED STANDARD PDF FONT", 15)
label(c, 30, 205, "Helvetica: ABCDEFGHIJKLMNOPQRSTUVWXYZ", 12)
label(c, 30, 176, "abcdefghijklmnopqrstuvwxyz 0123456789", 12)
c.setFont("Times-Roman", 15); c.drawString(30, 137, "Times-Roman: replacement font baseline")
c.setFont("Courier", 14); c.drawString(30, 100, "Courier: 0123456789 fixed pitch")
label(c, 30, 46, "Standard-14 fonts are intentionally not embedded.", 11)
c.save()
record("unembedded-font.pdf", 1, {"page_sizes_pt": [[400, 300]], "base_fonts": ["Helvetica", "Times-Roman", "Courier"], "font_embedded": False},
["This is a controlled Standard-14 substitution baseline, not arbitrary missing Japanese font coverage.", "Cross-OS fallback is not established by this Linux-only comparison."])
from icc_generator import generate as generate_icc
icc_record, manifest["color_profile"] = generate_icc(OUT)
manifest["documents"].append(icc_record)
(OUT / "manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(f"Generated {len(manifest['documents'])} PDF fixtures under {OUT}")
+15
View File
@@ -0,0 +1,15 @@
# Unembedded Japanese CID fixture
`unembedded-japanese.pdf` is authored locally by `../generate_fonts.py`, using
ReportLab's predefined Japanese CID fonts. The two pages select
`UniJIS-UCS2-H` and `UniJIS-UCS2-V` for HeiseiMin-W3 and HeiseiKakuGo-W5.
No font program is embedded. The second page uses the PDF vertical writing
mode, including native punctuation positioning, rather than individually
positioning horizontal glyphs. The text is synthetic and contains no third-party
document content. Font names identify requests; installed substitutes can differ.
The manifest records the input hash, authored text and page dimensions.
Generation requires ReportLab and pypdf. The generator checks both encoding
names and absence of FontFile/FontFile2/FontFile3 in the CID font descriptors.
Successful raster output alone does not establish character accuracy or full
CMap coverage; compare with Poppler and inspect both pages.
+33
View File
@@ -0,0 +1,33 @@
{
"schemaVersion": 1,
"generator": "generate_fonts.py (ReportLab UnicodeCIDFont, invariant PDF)",
"documents": [
{
"file": "unembedded-japanese.pdf",
"sha256": "9e74ac0c7d81a8c1d373cb28943a1943f8f68c0abd325e8e1012956bb71db057",
"pages": 2,
"sizePt": [
600,
760
],
"fontProgramsEmbedded": false,
"encodings": [
"/UniJIS-UCS2-H",
"/UniJIS-UCS2-V"
],
"faces": [
"HeiseiMin-W3",
"HeiseiKakuGo-W5"
],
"expectedText": [
"日本語の文書を表示します。",
"漢字とひらがな、カタカナ。",
"「縦書き」の句読点を確認。"
],
"writingModes": [
"horizontal",
"vertical"
]
}
]
}
+233
View File
@@ -0,0 +1,233 @@
%PDF-1.3
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 7 0 R /F6 8 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /HeiseiMin-W3 /DescendantFonts [ <<
/BaseFont /HeiseiMin-W3 /CIDSystemInfo <<
/Ordering (Japan1) /Registry (Adobe) /Supplement 2
>> /DW 1000 /FontDescriptor <<
/Ascent 723 /CapHeight 709 /Descent -241 /Flags 6 /FontBBox [ -123 -257 1001 910 ] /FontName /HeiseiMin-W3
/ItalicAngle 0 /StemV 69 /Type /FontDescriptor /XHeight 450
>> /Subtype /CIDFontType0 /Type /Font
/W [ 1 [ 250 333 408 500 ] 5 [ 500 833 778 180 333 ] 10 [ 333 500 564 250 333 250 278 500 ] 18 26 500 27
28 278 29 31 564 32 [ 444 921 722 667 ] 36 [ 667 722 611 556 722 ] 41
[ 722 333 389 722 611 889 722 ] 48 [ 722 556 722 667 556 611 722 ] 55 [ 722 944 722 ] 58 [ 722 611 333 500 333 469 500 333 444 500
444 500 444 333 500 ] 73 [ 500 278 ] 75
[ 278 500 278 778 500 ] 80 82 500 83 [ 333 389 278 500 ] 87 [ 500 722 500 ] 90 [ 500 444 480 200 480 333 ]
97 [ 278 ] 99 [ 200 ] 101 [ 333 500 ] 103 [ 500 167 ] 107 [ 500 ]
109 [ 500 333 ] 111 [ 333 556 ] 113 [ 556 500 ] 117 [ 250 ] 119 [ 350 333 444 ]
123 [ 500 ] 126 [ 444 333 ] 128 137 333 138 [ 1000 889 276 611 722 889 310 667 278 ] 147
[ 278 500 722 500 564 760 564 760 ] 157 158 300 159 [ 500 300 750 ] 162 163 750 164
169 722 170 [ 667 611 ] 172 174 611 175 178 333
179 185 722 187 191 722 192 [ 556 444 ] 194 203
444 204 207 278 208 214 500 216 222 500
223 [ 556 722 611 500 389 980 444 ] 231 [ 500 ] 323 [ 500 ] 325 [ 500 ] 327 389
500 ]
>> ] /Encoding /UniJIS-UCS2-H /Name /F3 /Subtype /Type0 /Type /Font
>>
endobj
5 0 obj
<<
/BaseFont /HeiseiKakuGo-W5 /DescendantFonts [ <<
/BaseFont /HeiseiKakuGo-W5 /CIDSystemInfo <<
/Ordering (Japan1) /Registry (Adobe) /Supplement 2
>> /DW 1000 /FontDescriptor <<
/Ascent 752 /CapHeight 737 /Descent -221 /Flags 4 /FontBBox [ -92 -250 1010 922 ] /FontName /HeiseKakuGo-W5
/ItalicAngle 0 /StemH 0 /StemV 114 /Type /FontDescriptor /XHeight 553
>> /Subtype /CIDFontType0 /Type /Font
/W [ 1 [ 277 305 500 668 668 906 727 305 445 445
508 668 305 379 305 539 ] 17 26 668 27 [ 305 305 668 668 668 566 871 727 637 652
699 574 555 676 687 242 492 664 582 789
707 734 582 734 605 605 641 668 727 945
609 609 574 445 668 445 668 668 590 555
609 547 602 574 391 609 582 234 277 539
234 895 582 605 602 602 387 508 441 582
562 781 531 570 555 449 246 449 668 ] 231 632 500 ]
>> ] /Encoding /UniJIS-UCS2-H /Name /F4 /Subtype /Type0 /Type /Font
>>
endobj
6 0 obj
<<
/Contents 13 0 R /MediaBox [ 0 0 600 760 ] /Parent 12 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
7 0 obj
<<
/BaseFont /HeiseiMin-W3 /DescendantFonts [ <<
/BaseFont /HeiseiMin-W3 /CIDSystemInfo <<
/Ordering (Japan1) /Registry (Adobe) /Supplement 2
>> /DW 1000 /FontDescriptor <<
/Ascent 723 /CapHeight 709 /Descent -241 /Flags 6 /FontBBox [ -123 -257 1001 910 ] /FontName /HeiseiMin-W3
/ItalicAngle 0 /StemV 69 /Type /FontDescriptor /XHeight 450
>> /Subtype /CIDFontType0 /Type /Font
/W [ 1 [ 250 333 408 500 ] 5 [ 500 833 778 180 333 ] 10 [ 333 500 564 250 333 250 278 500 ] 18 26 500 27
28 278 29 31 564 32 [ 444 921 722 667 ] 36 [ 667 722 611 556 722 ] 41
[ 722 333 389 722 611 889 722 ] 48 [ 722 556 722 667 556 611 722 ] 55 [ 722 944 722 ] 58 [ 722 611 333 500 333 469 500 333 444 500
444 500 444 333 500 ] 73 [ 500 278 ] 75
[ 278 500 278 778 500 ] 80 82 500 83 [ 333 389 278 500 ] 87 [ 500 722 500 ] 90 [ 500 444 480 200 480 333 ]
97 [ 278 ] 99 [ 200 ] 101 [ 333 500 ] 103 [ 500 167 ] 107 [ 500 ]
109 [ 500 333 ] 111 [ 333 556 ] 113 [ 556 500 ] 117 [ 250 ] 119 [ 350 333 444 ]
123 [ 500 ] 126 [ 444 333 ] 128 137 333 138 [ 1000 889 276 611 722 889 310 667 278 ] 147
[ 278 500 722 500 564 760 564 760 ] 157 158 300 159 [ 500 300 750 ] 162 163 750 164
169 722 170 [ 667 611 ] 172 174 611 175 178 333
179 185 722 187 191 722 192 [ 556 444 ] 194 203
444 204 207 278 208 214 500 216 222 500
223 [ 556 722 611 500 389 980 444 ] 231 [ 500 ] 323 [ 500 ] 325 [ 500 ] 327 389
500 ]
>> ] /Encoding /UniJIS-UCS2-V /Name /F5 /Subtype /Type0 /Type /Font
>>
endobj
8 0 obj
<<
/BaseFont /HeiseiKakuGo-W5 /DescendantFonts [ <<
/BaseFont /HeiseiKakuGo-W5 /CIDSystemInfo <<
/Ordering (Japan1) /Registry (Adobe) /Supplement 2
>> /DW 1000 /FontDescriptor <<
/Ascent 752 /CapHeight 737 /Descent -221 /Flags 4 /FontBBox [ -92 -250 1010 922 ] /FontName /HeiseKakuGo-W5
/ItalicAngle 0 /StemH 0 /StemV 114 /Type /FontDescriptor /XHeight 553
>> /Subtype /CIDFontType0 /Type /Font
/W [ 1 [ 277 305 500 668 668 906 727 305 445 445
508 668 305 379 305 539 ] 17 26 668 27 [ 305 305 668 668 668 566 871 727 637 652
699 574 555 676 687 242 492 664 582 789
707 734 582 734 605 605 641 668 727 945
609 609 574 445 668 445 668 668 590 555
609 547 602 574 391 609 582 234 277 539
234 895 582 605 602 602 387 508 441 582
562 781 531 570 555 449 246 449 668 ] 231 632 500 ]
>> ] /Encoding /UniJIS-UCS2-V /Name /F6 /Subtype /Type0 /Type /Font
>>
endobj
9 0 obj
<<
/Contents 14 0 R /MediaBox [ 0 0 600 760 ] /Parent 12 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
10 0 obj
<<
/PageMode /UseNone /Pages 12 0 R /Type /Catalog
>>
endobj
11 0 obj
<<
/Author (DocView synthetic test corpus) /CreationDate (D:20000101000000+00'00') /Creator (anonymous) /Keywords () /ModDate (D:20000101000000+00'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (unspecified) /Title (DocView unembedded Japanese CID H/V fixture) /Trapped /False
>>
endobj
12 0 obj
<<
/Count 2 /Kids [ 6 0 R 9 0 R ] /Type /Pages
>>
endobj
13 0 obj
<<
/Length 1124
>>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
BT /F2 16 Tf 19.2 TL ET
BT 1 0 0 1 36 722 Tm (Unembedded Japanese CID fonts) Tj T* ET
BT /F1 11 Tf 13.2 TL ET
BT 1 0 0 1 36 700 Tm (UniJIS-UCS2-H: horizontal writing mode) Tj T* ET
BT /F1 10 Tf 12 TL ET
BT 1 0 0 1 36 648 Tm (HeiseiMin-W3) Tj T* ET
BT /F3 20 Tf 24 TL ET
BT 1 0 0 1 36 610 Tm /F3 20 Tf 24 TL (e\345g,\212\2360ne\207f\3700\222\210hy:0W0~0Y0\002) Tj T* ET
BT 1 0 0 1 36 568 Tm /F3 20 Tf 24 TL (o"[W0h0r0\2110L0j0\0010\2530\2770\2530\3120\002) Tj T* ET
BT 1 0 0 1 36 526 Tm /F3 20 Tf 24 TL (0\014~&f\3700M0\0150nS\345\212\255p\2710\222x\272\212\2150\002) Tj T* ET
BT /F1 10 Tf 12 TL ET
BT 1 0 0 1 36 388 Tm (HeiseiKakuGo-W5) Tj T* ET
BT /F4 20 Tf 24 TL ET
BT 1 0 0 1 36 350 Tm /F4 20 Tf 24 TL (e\345g,\212\2360ne\207f\3700\222\210hy:0W0~0Y0\002) Tj T* ET
BT 1 0 0 1 36 308 Tm /F4 20 Tf 24 TL (o"[W0h0r0\2110L0j0\0010\2530\2770\2530\3120\002) Tj T* ET
BT 1 0 0 1 36 266 Tm /F4 20 Tf 24 TL (0\014~&f\3700M0\0150nS\345\212\255p\2710\222x\272\212\2150\002) Tj T* ET
BT /F1 9 Tf 10.8 TL ET
BT 1 0 0 1 36 28 Tm (Synthetic fixture / page 1 / no font program embedded) Tj T* ET
endstream
endobj
14 0 obj
<<
/Length 1224
>>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
BT /F2 16 Tf 19.2 TL ET
BT 1 0 0 1 36 722 Tm (Unembedded Japanese CID fonts) Tj T* ET
BT /F1 11 Tf 13.2 TL ET
BT 1 0 0 1 36 700 Tm (UniJIS-UCS2-V: native vertical writing mode) Tj T* ET
BT /F1 10 Tf 12 TL ET
BT 1 0 0 1 330 660 Tm (HeiseiMin-W3) Tj T* ET
BT /F5 20 Tf 24 TL ET
BT 1 0 0 1 520 620 Tm /F5 20 Tf 24 TL (e\345g,\212\2360ne\207f\3700\222\210hy:0W0~0Y0\002) Tj T* ET
BT /F5 20 Tf 24 TL ET
BT 1 0 0 1 458 620 Tm /F5 20 Tf 24 TL (o"[W0h0r0\2110L0j0\0010\2530\2770\2530\3120\002) Tj T* ET
BT /F5 20 Tf 24 TL ET
BT 1 0 0 1 396 620 Tm /F5 20 Tf 24 TL (0\014~&f\3700M0\0150nS\345\212\255p\2710\222x\272\212\2150\002) Tj T* ET
BT /F1 10 Tf 12 TL ET
BT 1 0 0 1 50 660 Tm (HeiseiKakuGo-W5) Tj T* ET
BT /F6 20 Tf 24 TL ET
BT 1 0 0 1 240 620 Tm /F6 20 Tf 24 TL (e\345g,\212\2360ne\207f\3700\222\210hy:0W0~0Y0\002) Tj T* ET
BT /F6 20 Tf 24 TL ET
BT 1 0 0 1 178 620 Tm /F6 20 Tf 24 TL (o"[W0h0r0\2110L0j0\0010\2530\2770\2530\3120\002) Tj T* ET
BT /F6 20 Tf 24 TL ET
BT 1 0 0 1 116 620 Tm /F6 20 Tf 24 TL (0\014~&f\3700M0\0150nS\345\212\255p\2710\222x\272\212\2150\002) Tj T* ET
BT /F1 9 Tf 10.8 TL ET
BT 1 0 0 1 36 28 Tm (Synthetic fixture / page 2 / no font program embedded) Tj T* ET
endstream
endobj
xref
0 15
0000000000 65535 f
0000000061 00000 n
0000000142 00000 n
0000000249 00000 n
0000000361 00000 n
0000001864 00000 n
0000002754 00000 n
0000002949 00000 n
0000004452 00000 n
0000005342 00000 n
0000005537 00000 n
0000005607 00000 n
0000005924 00000 n
0000005990 00000 n
0000007166 00000 n
trailer
<<
/ID
[<538e4832305af263a0a7344d39731b90><538e4832305af263a0a7344d39731b90>]
% ReportLab generated PDF document -- digest (opensource)
/Info 11 0 R
/Root 10 0 R
/Size 15
>>
startxref
8442
%%EOF
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""Generate DocView's small synthetic PDF corpus (no third-party content).
The coordinates, tags, appearances and security actions are intentional and are
asserted by test_pdf. qpdf is needed only to regenerate the encrypted fixture.
"""
from pathlib import Path
import subprocess
root = Path(__file__).parent
def stream(data, extra=''):
data = data.encode('ascii')
return f'<< /Length {len(data)} {extra} >>\nstream\n'.encode() + data + b'\nendstream'
def write_pdf(name, objects):
result = bytearray(b'%PDF-1.7\n%\xe2\xe3\xcf\xd3\n')
offsets = [0]
for index, obj in enumerate(objects, 1):
offsets.append(len(result))
if isinstance(obj, str): obj = obj.encode('ascii')
result += f'{index} 0 obj\n'.encode() + obj + b'\nendobj\n'
xref = len(result)
result += f'xref\n0 {len(offsets)}\n0000000000 65535 f \n'.encode()
for offset in offsets[1:]: result += f'{offset:010d} 00000 n \n'.encode()
result += f'trailer\n<< /Size {len(offsets)} /Root 1 0 R /Info 19 0 R >>\nstartxref\n{xref}\n%%EOF\n'.encode()
(root / name).write_bytes(result)
objects = [
'<< /Type /Catalog /Pages 2 0 R /Outlines 8 0 R /PageLabels << /Nums [0 << /S /r >> 1 << /S /D /St 1 >>] >> /StructTreeRoot 11 0 R /MarkInfo << /Marked true >> /AcroForm << /Fields [16 0 R] /DR << /Font << /F1 7 0 R >> >> /DA (/F1 12 Tf 0 g) >> /Names << /Dests << /Names [(second) [4 0 R /XYZ 40 200 null]] >> >> >>',
'<< /Type /Pages /Kids [3 0 R 4 0 R] /Count 2 >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 240 260] /CropBox [20 30 220 230] /Resources << /Font << /F1 7 0 R >> >> /Contents 5 0 R /StructParents 0 /Annots [14 0 R 15 0 R 16 0 R 18 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Rotate 90 /Resources << /Font << /F1 7 0 R >> >> /Contents 6 0 R >>',
stream('0 g 40 50 40 40 re f\n/Chapter <</MCID 0>> BDC BT /F1 16 Tf 60 180 Td (Heading One) Tj ET EMC\n/H2 <</MCID 1>> BDC BT /F1 12 Tf 60 120 Td (Needle) Tj ET EMC\n/H2 <</MCID 2>> BDC BT /F1 12 Tf 60 100 Td (Second MCID) Tj ET EMC'),
stream('BT /F1 20 Tf 40 100 Td (Second Page Needle) Tj ET'),
'<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>',
'<< /Type /Outlines /First 9 0 R /Last 10 0 R /Count 2 >>',
'<< /Title (First heading) /Parent 8 0 R /Dest [3 0 R /XYZ 60 180 null] /Next 10 0 R >>',
'<< /Title (Named second) /Parent 8 0 R /Dest (second) /Prev 9 0 R >>',
'<< /Type /StructTreeRoot /K [12 0 R 13 0 R] /RoleMap << /Chapter /H1 >> /ParentTree << /Nums [0 [12 0 R 13 0 R 13 0 R]] >> >>',
'<< /Type /StructElem /S /Chapter /P 11 0 R /Pg 3 0 R /K 0 >>',
'<< /Type /StructElem /S /H2 /P 11 0 R /Pg 3 0 R /K [1 2] >>',
'<< /Type /Annot /Subtype /Link /Rect [30 30 90 45] /A << /S /URI /URI (https://example.org/) >> >>',
'<< /Type /Annot /Subtype /Link /Rect [100 30 160 45] /A << /S /Launch /F (/tmp/never-execute) >> >>',
'<< /Type /Annot /Subtype /Widget /FT /Tx /T (ReadonlyField) /V (Saved) /Ff 1 /F 4 /Rect [120 60 160 90] /P 3 0 R /AP << /N 17 0 R >> >>',
stream('1 0 0 rg 0 0 40 30 re f', '/Type /XObject /Subtype /Form /BBox [0 0 40 30] /Resources << >>'),
'<< /Type /Annot /Subtype /Text /Rect [180 200 200 220] /Contents (Read-only comment) /F 4 >>',
'<< /Title (DocView PDF fixture) /Author (DocView tests) >>'
]
write_pdf('navigation.pdf', objects)
subprocess.run(['qpdf', '--encrypt', 'reader', 'owner-secret', '256', '--', str(root / 'navigation.pdf'), str(root / 'password.pdf')], check=True)
(root / 'corrupt.pdf').write_bytes(b'%PDF-1.7\nThis is deliberately corrupt.\n')
missing = list(objects)
missing[15] = missing[15].replace(' /AP << /N 17 0 R >>', '')
write_pdf('missing-appearance.pdf', missing)
reused = list(objects)
reused[2] = reused[2].replace('/Resources <<', '/Resources << /XObject << /Fm 20 0 R >>', 1)
reused[4] = stream('0 g /Chapter <</MCID 0>> BDC BT /F1 16 Tf 60 180 Td (Heading One) Tj ET EMC /Fm Do')
reused[11] = reused[11].replace('/S /Chapter', '/S /Chapter /T (Original Heading)')
reused.append(stream('/H1 <</MCID 0>> BDC BT /F1 12 Tf 50 50 Td (Different Form Heading) Tj ET EMC', '/Type /XObject /Subtype /Form /BBox [0 0 240 260] /Resources << /Font << /F1 7 0 R >> >>'))
write_pdf('reused-form-mcid.pdf', reused)
broken_pages = list(objects)
broken_pages[1] = broken_pages[1].replace('/Kids [3 0 R 4 0 R]', '/Kids [null 4 0 R]')
write_pdf('missing-first-page.pdf', broken_pages)
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""Deterministic, self-authored PDF annotation geometry; no external content."""
from pathlib import Path
import hashlib
import json
root = Path(__file__).parent / "annotation-flags"
root.mkdir(exist_ok=True)
objects = ["", ""]
def add(value):
objects.append(value.encode("ascii") if isinstance(value, str) else value)
return len(objects)
def stream(content, extra):
data = content.encode("ascii")
return add(f"<< /Length {len(data)} {extra} >>\nstream\n".encode() + data + b"\nendstream")
# Non-identity AP matrix, named graphics state, and selected appearance state
# must survive rectangle compensation. Normalization still yields red left /
# blue right in the annotation's 32x16 rectangle; Off is deliberately green.
normal = stream("q /Opaque gs 1 0 0 rg 0 0 16 16 re f 0 0 1 rg 16 0 16 16 re f Q",
"/Type /XObject /Subtype /Form /BBox [0 0 32 16] /Matrix [2 0 0 3 7 11] "
"/Resources << /ExtGState << /Opaque << /Type /ExtGState /ca 1 /CA 1 >> >> >>")
green = stream("0 1 0 rg 0 0 32 16 re f", "/Type /XObject /Subtype /Form /BBox [0 0 32 16] /Resources << >>")
pages, cases = [], []
def page(annots, rotate, case):
pid = add(f"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate {rotate} "
f"/Resources << >> /Annots [{' '.join(f'{x} 0 R' for x in annots)}] >>")
pages.append(pid)
cases.append(dict(page=len(pages)-1, intrinsicRotation=rotate, **case))
for kind in ["generated-link", "stored-link", "stored-comment"]:
for flags in [8, 16, 24]:
for rotate in [0, 90, 180, 270]:
extra = ("/C [1 0 0] /BS << /W 2 /S /S >>" if kind == "generated-link" else
f"/AP << /N << /On {normal} 0 R /Off {green} 0 R >> >> /AS /On")
subtype = "Stamp" if kind == "stored-comment" else "Link"
annot = add(f"<< /Type /Annot /Subtype /{subtype} /Rect [42 48 74 64] /F {flags} "
f"/Contents ({kind} flags {flags}) /A << /S /URI /URI (https://example.org/flags) >> {extra} >>")
page([annot], rotate, dict(kind=kind, flags=flags, rect=[42,48,74,64]))
# Annots order is retained: the later green appearance covers the generated
# border; Hidden / NoView appearances at distinct rectangles remain invisible.
annots = [add("<< /Type /Annot /Subtype /Link /Rect [42 48 74 64] /F 24 /C [1 0 0] /BS << /W 2 >> >>"),
add(f"<< /Type /Annot /Subtype /Link /Rect [41 47 75 65] /F 24 /AP << /N {green} 0 R >> >>")]
for flag, rect in [(26, "20 80 36 96"), (56, "80 80 96 96")]:
annots.append(add(f"<< /Type /Annot /Subtype /Link /Rect [{rect}] /F {flag} /Contents (Invisible comment) /AP << /N {normal} 0 R >> >>"))
page(annots, 0, dict(kind="visibility-zorder", flags=24))
# Right-edge clipping of an upright unscaled AP remains clipped to the CropBox.
edge = add(f"<< /Type /Annot /Subtype /Link /Rect [108 48 140 64] /F 24 /AP << /N {normal} 0 R >> >>")
page([edge], 0, dict(kind="crop-clipping", flags=24, rect=[108,48,140,64]))
objects[0] = b"<< /Type /Catalog /Pages 2 0 R >>"
objects[1] = f"<< /Type /Pages /Count {len(pages)} /Kids [{' '.join(f'{p} 0 R' for p in pages)}] >>".encode()
data = bytearray(b"%PDF-1.7\n%\xe2\xe3\xcf\xd3\n")
offsets = [0]
for index, value in enumerate(objects, 1):
offsets.append(len(data))
data += f"{index} 0 obj\n".encode() + value + b"\nendobj\n"
xref = len(data)
data += f"xref\n0 {len(offsets)}\n0000000000 65535 f \n".encode()
for offset in offsets[1:]: data += f"{offset:010d} 00000 n \n".encode()
data += f"trailer\n<< /Size {len(offsets)} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n".encode()
(root / "flags.pdf").write_bytes(data)
(root / "manifest.json").write_text(json.dumps(dict(generator="generate_annotation_flags.py",
license="Self-created test content; same license as DocView.", sha256=hashlib.sha256(data).hexdigest(),
cropBox=[8,12,120,116], cases=cases, expected="At 100% one PDF point is one logical pixel. "
"NoZoom preserves logical 32x16 size across zoom and scales only with DPR. NoRotate preserves upright "
"red-left/blue-right appearance around the original Rect upper-left through intrinsic plus user rotation. "
"Generated red border extends one point beyond Rect. This is synthetic geometry, not a general PDF compatibility golden."), indent=2)+"\n")
# Native Text icons have no supplied AP. Shared annotation objects exercise
# capture-once behavior across rotated pages without accumulating AP streams.
text_objects = [b"<< /Type /Catalog /Pages 2 0 R >>", b""]
text_content = b"BT /F1 10 Tf 12 100 Td (Native icon with unembedded body text) Tj ET"
text_objects.append(f"<< /Length {len(text_content)} >>\nstream\n".encode() + text_content + b"\nendstream")
text_objects.append(b"<< /Type /Annot /Subtype /Ink /Rect [80 24 100 34] /F 8 /Contents (Native ink) /BS << /W 4 >> /InkList [[80 24 90 34 100 24]] >>")
text_pages = []
for flags in [8,16,24]:
aid = len(text_objects) + 1
text_objects.append(f"<< /Type /Annot /Subtype /Text /Rect [42 48 74 64] /F {flags} /Contents (Native text icon) /C [1 0 0] >>".encode())
for rotation in [0,90,180,270]:
text_pages.append(len(text_objects)+1)
text_objects.append(f"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 128 128] /CropBox [8 12 120 116] /Rotate {rotation} "
f"/Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman >> >> >> /Contents 3 0 R /Annots [{aid} 0 R 4 0 R 4 0 R] >>".encode())
text_objects[1] = f"<< /Type /Pages /Count 12 /Kids [{' '.join(f'{p} 0 R' for p in text_pages)}] >>".encode()
data = bytearray(b"%PDF-1.7\n")
offsets = [0]
for index, value in enumerate(text_objects, 1):
offsets.append(len(data))
data += f"{index} 0 obj\n".encode() + value + b"\nendobj\n"
xref = len(data)
data += f"xref\n0 {len(offsets)}\n0000000000 65535 f \n".encode()
for offset in offsets[1:]: data += f"{offset:010d} 00000 n \n".encode()
data += f"trailer\n<< /Size {len(offsets)} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n".encode()
(root / "text-icons.pdf").write_bytes(data)
(root / "text-icons-manifest.json").write_text(json.dumps(dict(license="Self-created test content; same license as DocView.",
sha256=hashlib.sha256(data).hexdigest(), originalRect=[42,48,74,64], nativeIconRect=[42,48,62,68],
expected="Twelve pages: flags 8/16/24, each with intrinsic rotations 0/90/180/270. Four pages share each annotation. "
"Capture the native generated AP once, retain source Rect, use the captured 20x20 icon Rect for drawing and hit testing."), indent=2)+"\n")
+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env python3
"""Author one CMYK ICCBased PDF with a known four-dimensional Lab CLUT.
The ICC v2 input profile is encoded directly from the ICC specification;
no renderer/CMM output or borrowed press profile defines the expected values.
"""
import argparse
from io import BytesIO
import hashlib
import itertools
import json
from pathlib import Path
import struct
from pypdf import PdfReader, PdfWriter
from pypdf.generic import ArrayObject, DecodedStreamObject, DictionaryObject, NameObject, NumberObject
from reportlab.pdfgen import canvas
WIDTH, HEIGHT = 720, 420
SAMPLES = [(0, 0, 0, 0), (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0),
(0, 0, 0, 1), (.25, .5, .75, .2), (.6, .2, .4, .1), (1, 1, 1, 1)]
def model(cmyk):
c, m, y, k = cmyk
return 100 - 12*c - 15*m - 10*y - 35*k, 18*m - 15*c, 20*y - 12*c
def expected_rgb(cmyk):
# CIELAB inverse, D50 -> D65 Bradford adaptation, then standard sRGB.
lightness, a, b = model(cmyk)
fy = (lightness + 16) / 116
f = (fy + a/500, fy, fy - b/200)
xyz = [white * (v**3 if v > 6/29 else 3*(6/29)**2*(v-4/29))
for white, v in zip((.9642, 1, .8249), f)]
def multiply(matrix, vector):
return [sum(a*b for a, b in zip(row, vector)) for row in matrix]
d65 = multiply(((.9555766, -.0230393, .0631636), (-.0282895, 1.0099416, .0210077),
(.0122982, -.0204830, 1.3299098)), xyz)
linear = multiply(((3.2404542, -1.5371385, -.4985314), (-.969266, 1.8760108, .041556),
(.0556434, -.2040259, 1.0572252)), d65)
return [round(255*max(0, min(1, 12.92*v if v <= .0031308 else 1.055*v**(1/2.4)-.055))) for v in linear]
def profile_bytes():
def fixed(values):
return struct.pack('>' + 'i'*len(values), *(round(v*65536) for v in values))
header = bytearray(128)
header[8:12] = bytes.fromhex('02100000')
header[12:24] = b'scnrCMYKLab '
header[24:36] = struct.pack('>6H', 2026, 9, 20, 0, 0, 0)
header[36:40] = b'acsp'
header[68:80] = fixed((.9642, 1, .8249))
header[80:84] = b'DCVW'
description = b'DocView synthetic CMYK Lab CLUT\0'
desc = b'desc' + bytes(4) + struct.pack('>I', len(description)) + description + bytes(78)
copyright_tag = b'text' + bytes(4) + b'No copyright, use freely. Synthetic test profile; not a press characterization.\0'
table = bytearray(b'mft2' + bytes(4) + bytes((4, 3, 2, 0)))
table += fixed((1, 0, 0, 0, 1, 0, 0, 0, 1)) + struct.pack('>HH', 2, 2)
table += struct.pack('>HH', 0, 65535) * 4
for cmyk in itertools.product((0, 1), repeat=4):
lightness, a, b = model(cmyk)
table += struct.pack('>3H', round(lightness/100*65280), round((a+128)*256), round((b+128)*256))
table += struct.pack('>HH', 0, 65535) * 3
assert len(table) == 176
tags = [(b'desc', desc), (b'cprt', copyright_tag),
(b'wtpt', b'XYZ ' + bytes(4) + fixed((.9642, 1, .8249))), (b'A2B0', bytes(table))]
body = bytearray(); entries = bytearray(); offset = 132 + 12*len(tags)
for signature, data in tags:
entries += signature + struct.pack('>II', offset+len(body), len(data))
body += data + bytes((-len(data)) % 4)
result = header + struct.pack('>I', len(tags)) + entries + body
result[:4] = struct.pack('>I', len(result))
return bytes(result)
def generate(output):
output.mkdir(parents=True, exist_ok=False)
profile = profile_bytes()
(output / 'synthetic-cmyk-lab.icc').write_bytes(profile)
buffer = BytesIO()
page = canvas.Canvas(buffer, pagesize=(WIDTH, HEIGHT), invariant=1, pageCompression=0)
page.setTitle('ICC CMYK - four-dimensional lookup table')
page.setAuthor('DocView test corpus')
page.setFont('Helvetica-Bold', 18)
page.drawString(36, 385, 'ICC CMYK - FOUR-DIMENSIONAL LOOKUP TABLE')
page.setFont('Helvetica', 10)
page.drawString(36, 365, 'Synthetic CMYK to Lab mapping. Fixed D50 white point. No press calibration.')
for y, label in [(336, 'A ICCBased vector'), (238, 'B ICCBased image (8-bit components)'),
(140, 'C DeviceCMYK control (profile not applied)')]:
page.setFont('Helvetica-Bold', 10); page.drawString(36, y, label)
page.setFont('Helvetica', 9)
for i, label in enumerate(['White', 'Cyan', 'Magenta', 'Yellow', 'Black', 'Mix A', 'Mix B', 'All inks']):
page.drawCentredString(36+i*81+35, 48, label)
page.setFont('Helvetica', 9)
page.drawString(36, 25, 'A/B must agree with the analytic Lab mapping. C deliberately uses a different color space.')
page.save()
writer = PdfWriter(); writer.append(PdfReader(BytesIO(buffer.getvalue())))
target = writer.pages[0]
icc = DecodedStreamObject(); icc.set_data(profile)
icc.update({NameObject('/N'): NumberObject(4), NameObject('/Alternate'): NameObject('/DeviceCMYK')})
icc_ref = writer._add_object(icc)
space = ArrayObject([NameObject('/ICCBased'), icc_ref])
target['/Resources'][NameObject('/ColorSpace')] = DictionaryObject({NameObject('/TestCMYK'): space})
image = DecodedStreamObject(); image.set_data(bytes(round(v*255) for cmyk in SAMPLES for v in cmyk))
image.update({NameObject('/Type'): NameObject('/XObject'), NameObject('/Subtype'): NameObject('/Image'),
NameObject('/Width'): NumberObject(8), NameObject('/Height'): NumberObject(1),
NameObject('/BitsPerComponent'): NumberObject(8), NameObject('/ColorSpace'): space,
NameObject('/Intent'): NameObject('/RelativeColorimetric')})
target['/Resources'][NameObject('/XObject')] = DictionaryObject({NameObject('/Sample'): writer._add_object(image)})
probes, commands = [], ['/RelativeColorimetric ri']
for i, components in enumerate(SAMPLES):
x = 36+i*81
operands = ' '.join(f'{v:g}' for v in components)
commands += [f'/TestCMYK cs {operands} scn {x} 260 70 64 re f',
f'{operands} k {x} 64 70 64 re f']
probes.append({'kind': 'icc-vector', 'sample': i, 'pointPt': [x+35, 292], 'components': list(components),
'lab': list(model(components)), 'expectedRgb': expected_rgb(components)})
quantized = [round(v*255)/255 for v in components]
probes.append({'kind': 'icc-image', 'sample': i, 'pointPt': [36+(i+.5)*81, 194], 'components': quantized,
'lab': list(model(quantized)), 'expectedRgb': expected_rgb(quantized)})
probes.append({'kind': 'device-control', 'sample': i, 'pointPt': [x+35, 96], 'components': list(components)})
commands += ['q 648 0 0 64 36 162 cm /Sample Do Q']
content = DecodedStreamObject(); content.set_data(('\n'.join(commands)+'\n').encode())
target[NameObject('/Contents')] = ArrayObject([target.raw_get('/Contents'), writer._add_object(content)])
pdf = output / 'icc-cmyk-lut.pdf'
with pdf.open('wb') as stream: writer.write(stream)
def digest(data): return hashlib.sha256(data).hexdigest()
record = {'file': pdf.name, 'sha256': digest(pdf.read_bytes()), 'profileFile': 'synthetic-cmyk-lab.icc',
'profileSha256': digest(profile), 'profileBytes': len(profile), 'pageSizePt': [WIDTH, HEIGHT],
'profile': {'version': '2.1', 'class': 'scnr', 'input': 'CMYK', 'pcs': 'Lab ',
'tag': 'A2B0', 'type': 'mft2', 'gridPointsPerChannel': 2,
'mapping': ['L=100-12*C-15*M-10*Y-35*K', 'a=18*M-15*C', 'b=20*Y-12*C'],
'labEncoding': 'ICC v2 L: 0..65280 for 0..100; a/b: (value+128)*256',
'source': 'Self-authored binary ICC input profile; no borrowed ICC profile'},
'probes': probes, 'tolerance8Bit': 4,
'references': ['https://archive.color.org/files/icc32.pdf', 'https://www.color.org/chardata/rgb/srgb.xalter'],
'limits': ['Synthetic CMYK input CLUT; not a measured print profile or calibrated press proof.',
'No human-approved golden; no physical display or Windows validation.'],
'generatorSha256': digest(Path(__file__).read_bytes())}
(output / 'manifest.json').write_text(json.dumps(record, indent=2) + '\n')
print(json.dumps({'fixtureSha256': record['sha256'], 'profileSha256': record['profileSha256'], 'probes': len(probes)}))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--output', type=Path, required=True)
generate(parser.parse_args().output)
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
"""Generate synthetic read-only comment keyboard fixtures, without dependencies."""
from pathlib import Path
objects = [
b'<< /Type /Catalog /Pages 2 0 R >>',
b'<< /Type /Pages /Kids [3 0 R] /Count 1 >>',
b'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 240 260] /CropBox [20 30 220 230] /Annots [4 0 R 5 0 R] /Resources << >> >>',
b'<< /Type /Annot /Subtype /Text /Rect [100 100 120 120] /Contents (<b>Literal comment</b>) /F 4 >>',
b'<< /Type /Annot /Subtype /Text /Rect [1000 1000 1020 1020] /Contents (Outside CropBox comment) /F 4 >>',
]
data = bytearray(b'%PDF-1.7\n%\xe2\xe3\xcf\xd3\n')
offsets = [0]
for index, obj in enumerate(objects, 1):
offsets.append(len(data))
data += f'{index} 0 obj\n'.encode() + obj + b'\nendobj\n'
xref = len(data)
data += f'xref\n0 {len(offsets)}\n0000000000 65535 f \n'.encode()
for offset in offsets[1:]:
data += f'{offset:010d} 00000 n \n'.encode()
data += f'trailer\n<< /Size {len(offsets)} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n'.encode()
Path(__file__).with_name('comments.pdf').write_bytes(data)
# Sub-pixel page at 25% zoom: keyboard focus must not invert scroll bounds.
tiny = bytes(data)
for original, replacement in [(b'[0 0 240 260]', b'[0 0 1 1]'),
(b'[20 30 220 230]', b'[0 0 1 1]'),
(b'[100 100 120 120]', b'[0 0 0.5 0.5]'),
(b'[1000 1000 1020 1020]', b'[0 0 0.5 0.5]')]:
tiny = tiny.replace(original, replacement.ljust(len(original), b' '))
# Preserve fixed byte widths so the original xref remains exact.
assert len(tiny) == len(data)
Path(__file__).with_name('tiny-comments.pdf').write_bytes(tiny)
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""Author deterministic unembedded Japanese CID H/V fixtures (ReportLab)."""
import hashlib
import json
from pathlib import Path
from pypdf import PdfReader
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
from reportlab.pdfgen.canvas import Canvas
ROOT = Path(__file__).resolve().parent / "fonts"
ROOT.mkdir(exist_ok=True)
OUTPUT = ROOT / "unembedded-japanese.pdf"
TEXTS = ["日本語の文書を表示します。", "漢字とひらがな、カタカナ。", "「縦書き」の句読点を確認。"]
for face in ("HeiseiMin-W3", "HeiseiKakuGo-W5"):
for vertical in (False, True):
font = UnicodeCIDFont(face, isVertical=vertical)
font.name = font.fontName = face + ("-V" if vertical else "-H")
pdfmetrics.registerFont(font)
canvas = Canvas(str(OUTPUT), pagesize=(600, 760), invariant=1, pageCompression=0)
canvas.setTitle("DocView unembedded Japanese CID H/V fixture")
canvas.setAuthor("DocView synthetic test corpus")
for page, vertical in enumerate((False, True), 1):
canvas.setFont("Helvetica-Bold", 16)
canvas.drawString(36, 722, "Unembedded Japanese CID fonts")
canvas.setFont("Helvetica", 11)
canvas.drawString(36, 700, "UniJIS-UCS2-" + ("V: native vertical writing mode" if vertical else "H: horizontal writing mode"))
for row, face in enumerate(("HeiseiMin-W3", "HeiseiKakuGo-W5")):
canvas.setFont("Helvetica", 10)
if vertical:
canvas.drawString(330 - row * 280, 660, face)
for col, text in enumerate(TEXTS):
canvas.setFont(face + "-V", 20)
canvas.drawString(520 - row * 280 - col * 62, 620, text)
else:
canvas.drawString(36, 648 - row * 260, face)
canvas.setFont(face + "-H", 20)
for line, text in enumerate(TEXTS):
canvas.drawString(36, 610 - row * 260 - line * 42, text)
canvas.setFont("Helvetica", 9)
canvas.drawString(36, 28, f"Synthetic fixture / page {page} / no font program embedded")
canvas.showPage()
canvas.save()
reader = PdfReader(OUTPUT)
encodings = set()
for page in reader.pages:
for ref in page["/Resources"]["/Font"].values():
font = ref.get_object()
if font.get("/Subtype") != "/Type0":
continue
encodings.add(str(font["/Encoding"]))
for descendant in font["/DescendantFonts"]:
descriptor = descendant.get_object()["/FontDescriptor"].get_object()
assert not any(key in descriptor for key in ("/FontFile", "/FontFile2", "/FontFile3"))
assert encodings == {"/UniJIS-UCS2-H", "/UniJIS-UCS2-V"}, encodings
manifest = {
"schemaVersion": 1,
"generator": "generate_fonts.py (ReportLab UnicodeCIDFont, invariant PDF)",
"documents": [{
"file": OUTPUT.name,
"sha256": hashlib.sha256(OUTPUT.read_bytes()).hexdigest(),
"pages": 2,
"sizePt": [600, 760],
"fontProgramsEmbedded": False,
"encodings": sorted(encodings),
"faces": ["HeiseiMin-W3", "HeiseiKakuGo-W5"],
"expectedText": TEXTS,
"writingModes": ["horizontal", "vertical"],
}],
}
(ROOT / "manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n")
print(json.dumps(manifest, ensure_ascii=False, indent=2))
+230
View File
@@ -0,0 +1,230 @@
#!/usr/bin/env python3
"""Deterministic, self-authored tagged-PDF boundary corpus (no external tools)."""
from pathlib import Path
import hashlib
import json
import zlib
ROOT = Path(__file__).parent / 'headings'
ROOT.mkdir(exist_ok=True)
def stream(text, extra=''):
data = text.encode('ascii')
return f'<< /Length {len(data)} {extra} >>\nstream\n'.encode() + data + b'\nendstream'
def write(name, objects, expected):
data = bytearray(b'%PDF-1.7\n%\xe2\xe3\xcf\xd3\n')
offsets = [0]
for number, obj in enumerate(objects, 1):
offsets.append(len(data))
data += f'{number} 0 obj\n'.encode() + (obj.encode('ascii') if isinstance(obj, str) else obj) + b'\nendobj\n'
xref = len(data)
data += f'xref\n0 {len(offsets)}\n0000000000 65535 f \n'.encode()
for offset in offsets[1:]:
data += f'{offset:010d} 00000 n \n'.encode()
data += f'trailer\n<< /Size {len(offsets)} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n'.encode()
(ROOT / name).write_bytes(data)
return {'file': name, 'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest(), 'expected': expected}
font = '<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>'
records = []
records.append(write('transformed-form.pdf', [
'<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 7 0 R >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 0 /Resources << /XObject << /Fm 6 0 R >> >> /Contents 4 0 R >>',
stream('/H2 <</MCID 0>> BDC q 1.5 0 0 1.25 55 70 cm /Fm Do Q EMC'),
font,
stream('/H2 <</MCID 4>> BDC BT /F1 16 Tf 10 30 Td (Form heading) Tj ET EMC', '/Type /XObject /Subtype /Form /BBox [0 0 160 80] /StructParents 1 /Resources << /Font << /F1 5 0 R >> >>'),
'<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Nums [0 [8 0 R] 1 [null null null null 8 0 R]] >> /ParentTreeNextKey 2 >>',
'<< /Type /StructElem /S /H2 /P 7 0 R /Pg 3 0 R /T (Form heading) /K [0 << /Type /MCR /Pg 3 0 R /Stm 6 0 R /MCID 4 >>] >>'
], {'pages': 1, 'headings': [{'page': 0, 'title': 'Form heading', 'level': 2, 'precision': 'exact', 'text_region_pt': [70, 102, 240, 130]}], 'form_matrix': [1.5, 0, 0, 1.25, 55, 70], 'local_baseline': [10, 30]}))
records.append(write('rotated-tags.pdf', [
'<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 260] /CropBox [20 30 280 230] /Rotate 90 /StructParents 0 /Resources << /Font << /F1 5 0 R >> >> /Contents 4 0 R >>',
stream('/H3 <</MCID 1>> BDC BT /F1 16 Tf 60 80 Td (Rotated second) Tj ET EMC\n/H1 <</MCID 0>> BDC BT /F1 20 Tf 50 170 Td (Rotated first) Tj ET EMC'),
font,
'<< /Type /StructTreeRoot /K [7 0 R 8 0 R] /ParentTree << /Nums [0 [7 0 R 8 0 R]] >> >>',
'<< /Type /StructElem /S /H1 /P 6 0 R /Pg 3 0 R /K 0 >>',
'<< /Type /StructElem /S /H3 /P 6 0 R /Pg 3 0 R /K 1 >>'
], {'pages': 1, 'crop_box': [20, 30, 280, 230], 'rotation': 90, 'headings': [
{'page': 0, 'title': 'Rotated first', 'level': 1, 'precision': 'exact', 'text_region_pt': [50, 168, 170, 190]},
{'page': 0, 'title': 'Rotated second', 'level': 3, 'precision': 'exact', 'text_region_pt': [60, 78, 180, 96]}
], 'order': 'structure order, intentionally different from content-stream draw order'}))
records.append(write('cross-page-structure.pdf', [
'<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 8 0 R >>',
'<< /Type /Pages /Count 2 /Kids [3 0 R 4 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 0 /Resources << /Font << /F1 7 0 R >> >> /Contents 5 0 R >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 1 /Resources << /Font << /F1 7 0 R >> >> /Contents 6 0 R >>',
stream('/Span <</MCID 0>> BDC BT /F1 16 Tf 40 60 Td (Across page one) Tj ET EMC\n/H1 <</MCID 1>> BDC BT /F1 16 Tf 170 60 Td ( middle) Tj ET EMC'),
stream('/P <</MCID 2>> BDC BT /F1 16 Tf 40 120 Td (Unrelated paragraph) Tj ET EMC\n/H2 <</MCID 1>> BDC BT /F1 16 Tf 40 160 Td (Following heading) Tj ET EMC\n/Span <</MCID 0>> BDC BT /F1 16 Tf 40 210 Td (Across page two) Tj ET EMC'),
font,
'<< /Type /StructTreeRoot /K [9 0 R] /ParentTree << /Nums [0 [12 0 R 10 0 R] 1 [13 0 R 11 0 R 14 0 R]] >> /ParentTreeNextKey 2 >>',
'<< /Type /StructElem /S /Sect /P 8 0 R /K [10 0 R 11 0 R 14 0 R] >>',
'<< /Type /StructElem /S /H1 /P 9 0 R /T (Across pages) /K [12 0 R << /Type /MCR /Pg 3 0 R /MCID 1 >> 13 0 R] >>',
'<< /Type /StructElem /S /H2 /P 9 0 R /Pg 4 0 R /K 1 >>',
'<< /Type /StructElem /S /Span /P 10 0 R /Pg 3 0 R /K 0 >>',
'<< /Type /StructElem /S /Span /P 10 0 R /Pg 4 0 R /K 0 >>',
'<< /Type /StructElem /S /P /P 9 0 R /Pg 4 0 R /K 2 >>'
], {'pages': 2, 'headings': [
{'page': 0, 'title': 'Across page one middle', 'level': 1, 'precision': 'exact', 'text_region_pt': [40, 55, 230, 78]},
{'page': 1, 'title': 'Across page two', 'level': 1, 'precision': 'exact', 'text_region_pt': [40, 205, 170, 228]},
{'page': 1, 'title': 'Following heading', 'level': 2, 'precision': 'exact', 'text_region_pt': [40, 155, 180, 178]}
], 'scope': 'One heading spans two page-local Span elements with an interleaved direct MCR; MCID 0 is reused independently on both pages. Results are page-local fragments.'}))
records.append(write('vector-heading.pdf', [
'<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 5 0 R >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 0 /Resources << >> /Contents 4 0 R >>',
stream('/H4 <</MCID 0>> BDC 0 0 1 rg 40 180 150 20 re f EMC'),
'<< /Type /StructTreeRoot /K [6 0 R] /ParentTree << /Nums [0 [6 0 R]] >> >>',
'<< /Type /StructElem /S /H4 /P 5 0 R /Pg 3 0 R /ActualText (Vector section) /K 0 >>'
], {'pages': 1, 'headings': [{'page': 0, 'title': 'Vector section', 'level': 4, 'precision': 'page', 'reason_contains': '座標'}], 'drawn_region_pt': [40, 180, 190, 200], 'fallback': 'No text glyph bounding box is available for the marked vector path.'}))
records.append(write('form-only-structure.pdf', [
'<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 7 0 R >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /Resources << /XObject << /Fm 6 0 R >> >> /Contents 4 0 R >>',
stream('q 1 0 0 1 40 100 cm /Fm Do Q'),
font,
stream('/H2 <</MCID 0>> BDC BT /F1 16 Tf 10 30 Td (Form only heading) Tj ET EMC', '/Type /XObject /Subtype /Form /BBox [0 0 200 80] /StructParents 0 /Resources << /Font << /F1 5 0 R >> >>'),
'<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Nums [0 [8 0 R]] >> /ParentTreeNextKey 1 >>',
'<< /Type /StructElem /S /H2 /P 7 0 R /Pg 3 0 R /T (Form only heading) /K << /Type /MCR /Pg 3 0 R /Stm 6 0 R /MCID 0 >> >>'
], {'pages': 1, 'headings': [{'page': 0, 'title': 'Form only heading', 'level': 2, 'precision': 'exact', 'text_region_pt': [50, 125, 190, 147]}],
'scope': 'Form StructParents and source-qualified MCR; no page StructParents.'}))
records.append(write('form-vector-mcid-collision.pdf', [
'<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 7 0 R >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 0 /Resources << /XObject << /Fm 6 0 R >> >> /Contents 4 0 R >>',
stream('/H1 <</MCID 0>> BDC 0 0 1 rg 40 180 180 20 re f EMC q 1 0 0 1 40 100 cm /Fm Do Q'),
font,
stream('/P <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Unrelated Form paragraph) Tj ET EMC', '/Type /XObject /Subtype /Form /BBox [0 0 240 80] /StructParents 1 /Resources << /Font << /F1 5 0 R >> >>'),
'<< /Type /StructTreeRoot /K [8 0 R 9 0 R] /ParentTree << /Nums [0 [8 0 R] 1 [9 0 R]] >> /ParentTreeNextKey 2 >>',
'<< /Type /StructElem /S /H1 /P 7 0 R /Pg 3 0 R /T (Page vector heading) /K 0 >>',
'<< /Type /StructElem /S /P /P 7 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 6 0 R /MCID 0 >> >>'
], {'pages': 1, 'headings': [{'page': 0, 'title': 'Page vector heading', 'level': 1, 'precision': 'page', 'reason_contains': 'MCID'}],
'fallback': 'MCID 0 names a page vector and unrelated Form text. Non-text page objects must participate in stream collision detection.'}))
def form_case(name, forms, content, expected, *, rolemap='', root_order=None, mutate=None):
"""Create source-qualified MCRs with an indirect ParentTree Kids node."""
objects = ['<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>', '', stream(content), font, '']
heading_ids = [7 + len(forms) + i for i, form in enumerate(forms)]
names = ' '.join(f'/Fm{i} {7+i} 0 R' for i in range(len(forms)))
objects[2] = f'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << {names} >> >> /Contents 4 0 R >>'
for i, form in enumerate(forms):
extra = f'/Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents {i} /Resources << /Font << /F1 5 0 R >> /XObject << {names} >> /Properties << /HeadingProperty << /MCID 0 >> >> >>'
if 'matrix' in form: extra += f' /Matrix [{form["matrix"]}]'
objects.append(stream(form['content'], extra))
for i, form in enumerate(forms):
title = f'/T ({form["title"]})' if 'title' in form else ''
objects.append(f'<< /Type /StructElem /S /{form.get("role", "H2")} /P 6 0 R /Pg 3 0 R {title} /K << /Type /MCR /Pg 3 0 R /Stm {7+i} 0 R /MCID 0 >> >>')
parent_id = len(objects) + 1
nums = ' '.join(f'{i} [{heading_ids[i]} 0 R]' for i in range(len(forms)))
objects.append(f'<< /Limits [0 {len(forms)-1}] /Nums [{nums}] >>')
order = root_order if root_order is not None else range(len(forms))
children = ' '.join(f'{heading_ids[i]} 0 R' for i in order)
objects[5] = f'<< /Type /StructTreeRoot /K [{children}] /ParentTree << /Kids [{parent_id} 0 R] >> {rolemap} >>'
if mutate: mutate(objects, heading_ids)
records.append(write(name, objects, {'pages': 1, **expected}))
def tagged(label, tag='H2'):
return f'/{tag} <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td ({label}) Tj ET EMC'
def exact(title, region, level=2):
return {'page': 0, 'title': title, 'level': level, 'precision': 'exact', 'text_region_pt': region}
def fallback(title, reason):
return {'page': 0, 'title': title, 'level': 2, 'precision': 'page', 'reason_contains': reason}
form_case('named-property-rolemap.pdf', [{'content': '/Section /HeadingProperty BDC BT /F1 12 Tf 10 30 Td (Named property heading) Tj ET EMC', 'role': 'Section'}],
'q 1 0 0 1 40 100 cm /Fm0 Do Q', {'headings': [exact('Named property heading', [50, 127, 190, 142], 3)]}, rolemap='/RoleMap << /Section /H3 >>')
form_case('nested-form-matrix.pdf', [{'content': 'q 1.5 0 0 1.25 10 20 cm /Fm1 Do Q', 'matrix': '1.2 0 0 0.9 5 7'},
{'content': tagged('Nested heading'), 'matrix': '1 0 0 1 4 6'}],
'q 1 0 0 1 40 100 cm /Fm0 Do Q', {'headings': [exact('Nested heading', [82, 161, 245, 181])]})
form_case('different-form-same-mcid.pdf', [{'content': tagged('First form')}, {'content': tagged('Second form')}],
'q 1 0 0 1 30 180 cm /Fm0 Do Q q 1 0 0 1 80 60 cm /Fm1 Do Q',
{'headings': [exact('Second form', [90, 87, 170, 102]), exact('First form', [40, 207, 105, 222])]}, root_order=[1, 0])
form_case('ambiguous-form-matrix.pdf', [{'content': tagged('Do not borrow first'), 'title': 'First structure'}, {'content': tagged('Do not borrow second'), 'title': 'Second structure'}],
'q 1 0 0 1 40 100 cm /Fm0 Do /Fm1 Do Q',
{'headings': [fallback('First structure', '一意'), fallback('Second structure', '一意')]})
form_case('repeated-form.pdf', [{'content': tagged('Repeated heading')}],
'q 1 0 0 1 30 180 cm /Fm0 Do Q q 1 0 0 1 80 60 cm /Fm0 Do Q',
{'headings': [fallback('Repeated heading', '複数回')]})
form_case('unused-form-resource.pdf', [{'content': tagged('Used heading')}, {'content': tagged('Unused heading')}],
'q 1 0 0 1 40 100 cm /Fm0 Do Q', {'headings': [exact('Used heading', [50, 127, 140, 142])]})
form_case('inline-image-before-form.pdf', [{'content': tagged('After image')}],
'q 1 0 0 1 40 100 cm BI /W 1 /H 1 /BPC 8 /CS /G ID X EI /Fm0 Do Q',
{'headings': [exact('After image', [50, 127, 125, 142])]})
limited = {'headings': [], 'limited': True}
form_case('cyclic-form.pdf', [{'content': '/Fm0 Do'}], '/Fm0 Do', limited)
form_case('cyclic-rolemap.pdf', [{'content': tagged('Hidden by cycle'), 'role': 'Foo'}], '/Fm0 Do', limited, rolemap='/RoleMap << /Foo /Bar /Bar /Foo >>')
form_case('cyclic-parent.pdf', [{'content': tagged('Parent cycle')}], '/Fm0 Do', limited,
mutate=lambda o, ids: o.__setitem__(ids[0]-1, o[ids[0]-1].replace('/P 6 0 R', f'/P {ids[0]} 0 R')))
form_case('cyclic-children.pdf', [{'content': tagged('Child cycle')}], '/Fm0 Do', limited,
mutate=lambda o, ids: o.__setitem__(ids[0]-1, f'<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K {ids[0]} 0 R >>'))
form_case('broken-mcr-page.pdf', [{'content': tagged('Wrong page')}], '/Fm0 Do', limited,
mutate=lambda o, ids: o.__setitem__(ids[0]-1, o[ids[0]-1].replace('/Type /MCR /Pg 3 0 R', '/Type /MCR /Pg 7 0 R')))
form_case('broken-mcr-stream.pdf', [{'content': tagged('Wrong stream')}], '/Fm0 Do', limited,
mutate=lambda o, ids: o.__setitem__(ids[0]-1, o[ids[0]-1].replace('/Stm 7 0 R', '/Stm 3 0 R')))
form_case('annotation-owned-mcr.pdf', [{'content': tagged('Annotation-owned')}], '/Fm0 Do', limited,
mutate=lambda o, ids: o.__setitem__(ids[0]-1, o[ids[0]-1].replace('/Stm 7 0 R', '/Stm 7 0 R /StmOwn 3 0 R')))
form_case('broken-graphics-stack.pdf', [{'content': tagged('Graphics stack')}], 'Q /Fm0 Do', limited)
form_case('cyclic-number-tree.pdf', [{'content': tagged('Number tree')}], '/Fm0 Do', limited,
mutate=lambda o, ids: o.__setitem__(len(o)-1, f'<< /Limits [0 0] /Kids [{len(o)} 0 R] >>'))
form_case('conflicting-parent-tree-owner.pdf', [{'content': tagged('First owner')}, {'content': tagged('Second owner')}],
'q 1 0 0 1 30 180 cm /Fm0 Do Q q 1 0 0 1 80 60 cm /Fm1 Do Q', limited,
mutate=lambda o, ids: o.__setitem__(ids[0]-1, o[ids[0]-1].replace('/Stm 7 0 R', '/Stm 8 0 R')))
def compressed_content(size):
def mutate(objects, ids):
body = ('q 1 0 0 1 40 100 cm /Fm0 Do Q').encode()
data = zlib.compress(b' ' * (size-len(body)) + body)
objects[3] = f'<< /Length {len(data)} /Filter /FlateDecode >>\nstream\n'.encode() + data + b'\nendstream'
return mutate
form_case('stream-quota-at-limit.pdf', [{'content': tagged('At stream limit')}], '',
{'headings': [exact('At stream limit', [50, 127, 140, 142])]}, mutate=compressed_content(16*1024*1024))
form_case('stream-quota-over-limit.pdf', [{'content': tagged('Over stream limit')}], '',
{'headings': [], 'limited': True, 'truncated': True}, mutate=compressed_content(16*1024*1024+1))
long_title = '<feff' + ('あ' * 4090).encode('utf-16-be').hex() + '>'
many = ['<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 5 0 R >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /StructParents 0 /Resources << >> /Contents 4 0 R >>',
stream('\n'.join(f'/H2 <</MCID {i}>> BDC 10 {i*4} 20 2 re f EMC' for i in range(70))), '']
for i in range(70):
many.append(f'<< /Type /StructElem /S /H2 /P 5 0 R /Pg 3 0 R /K {i} /ActualText {long_title} >>')
refs = ' '.join(f'{i+6} 0 R' for i in range(70))
many[4] = f'<< /Type /StructTreeRoot /K [{refs}] /ParentTree << /Nums [0 [{refs}]] >> >>'
records.append(write('bounded-heading-response.pdf', many, {'pages': 1, 'headings': [], 'response_limited': True}))
deep = ['<< /Type /Catalog /Pages 2 0 R >>', '<< /Type /Pages /Count 2 /Kids [3 0 R 70 0 R] >>']
for obj in range(3, 69):
deep.append(f'<< /Type /Pages /Parent {obj-1} 0 R /Count 1 /Kids [{obj+1} 0 R] >>')
deep.append('<< /Type /Page /Parent 68 0 R /MediaBox [0 0 100 100] /Resources << >> >>')
deep.append('<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Resources << >> >>')
context_record = write('context-deep-tree.pdf', deep, {'scope': 'Context-only regression: after a depth failure, the second page must never be assigned index zero.'})
context_records = [context_record]
for count in (32, 33):
context_records.append(write(f'context-warnings-{count}.pdf', [
f'<< /Type /Catalog /Pages 2 0 R /Duplicate 1 /Duplicate 2 /Probe [' + ' '.join(f'{i+4} 0 R' for i in range(count-1)) + '] >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> >>'] +
['<< /Duplicate 1 /Duplicate 2 >>'] * (count-1),
{'scope': 'Context-only cumulative diagnostic limit, starting in initial parse; warning bodies must never reach stdout/stderr.', 'accepted': count == 32}))
long_key = '/' + 'A' * (64*1024)
context_records.append(write('context-warning-bytes.pdf', [
f'<< /Type /Catalog /Pages 2 0 R {long_key} 1 {long_key} 2 >>',
'<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> >>'],
{'scope': 'Context-only diagnostic byte limit during initial parse; no warning text is retained or emitted.', 'accepted': False}))
(ROOT / 'manifest.json').write_text(json.dumps({'origin': 'Self-created deterministic PDF syntax, Helvetica Standard-14 text and vector paths; no third-party document content.', 'generator': '../generate_headings.py', 'documents': records, 'context_documents': context_records}, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
print(f'Generated {len(records)} heading fixtures in {ROOT}')
+214
View File
@@ -0,0 +1,214 @@
#!/usr/bin/env python3
"""Self-authored RI probes for luminosity masks and pattern initial state."""
import argparse
import hashlib
import json
from pathlib import Path
from pypdf import PdfWriter
from pypdf.generic import (ArrayObject, BooleanObject, DecodedStreamObject,
DictionaryObject, FloatObject, NameObject, NumberObject)
ROOT = Path(__file__).resolve().parents[3]
SOURCE = ROOT / 'tests/fixtures/pdf/rendering-intents/distinct-cmyk-lab.icc'
PROFILE_SHA = 'b9a40bfc18e8280eefe0fedc4e607467e1cc27adeee3beb77f4a2b83fc7e9315'
INTENTS = ('Perceptual', 'RelativeColorimetric', 'Saturation', 'AbsoluteColorimetric')
SAMPLE = (0, .75, .25, 0)
WIDTH, HEIGHT = 880, 850
CASES = (
'direct-icc-control', 'mask-caller-ri', 'mask-internal-ri', 'mask-internal-gs',
'mask-group-qQ', 'mask-q-inner-none', 'mask-Q-restores', 'mask-none',
'mask-BC-only', 'mask-opaque-over-BC',
'tiling-page-initial', 'tiling-colored-ri', 'tiling-colored-gs', 'tiling-colored-qQ',
'tiling-form-initial', 'tiling-form-initial-reuse', 'tiling-form-ri',
'tiling-uncolored-fill', 'tiling-uncolored-fill-gs',
'tiling-uncolored-stroke-small', 'tiling-uncolored-stroke-large',
'shading-page-initial', 'shading-pattern-ri', 'shading-form-initial',
'shading-form-initial-reuse', 'shading-form-ri', 'direct-shading-control',
)
def digest(data): return hashlib.sha256(data).hexdigest()
def n(value): return NameObject('/' + value)
def a(values): return ArrayObject([FloatObject(v) for v in values])
def d(**values): return DictionaryObject({n(k): v for k, v in values.items()})
def numbers(values): return ' '.join(format(v, '.10g') for v in values)
def generate(output):
output.mkdir(parents=True, exist_ok=False)
profile = SOURCE.read_bytes()
assert digest(profile) == PROFILE_SHA
(output / SOURCE.name).write_bytes(profile)
writer = PdfWriter(); writer.pdf_header = '%PDF-1.7'
writer.add_metadata({'/Title': 'Rendering intent: soft masks and pattern initial state',
'/Author': 'DocView synthetic regression corpus'})
def stream(data, **entries):
obj = DecodedStreamObject(); obj.set_data(data.encode() if isinstance(data, str) else data)
obj.update(d(**entries)); return writer._add_object(obj)
cs = ArrayObject([n('ICCBased'), stream(profile, N=NumberObject(4), Alternate=n('DeviceCMYK'))])
colors = d(CS=cs, PCS=ArrayObject([n('Pattern'), cs]))
gs = d(**{'I'+str(i): d(Type=n('ExtGState'), RI=n(intent)) for i, intent in enumerate(INTENTS)})
gs[n('NoMask')] = d(Type=n('ExtGState'), SMask=n('None'))
font = writer._add_object(d(Type=n('Font'), Subtype=n('Type1'), BaseFont=n('Helvetica')))
base = d(ColorSpace=colors, ExtGState=gs)
paint = '/CS cs ' + numbers(SAMPLE) + ' scn '
group_attributes = d(S=n('Transparency'), CS=n('DeviceRGB'), I=BooleanObject(True), K=BooleanObject(False))
def group(prefix='', empty=False):
return stream(prefix + '\n' + ('' if empty else paint + f'0 0 {WIDTH} {HEIGHT} re f\n'),
Type=n('XObject'), Subtype=n('Form'), BBox=a((0,0,WIDTH,HEIGHT)),
Group=group_attributes, Resources=base)
shared_group = group()
empty_group = group(empty=True)
def mask(name, group_ref, bc=(0,0,0)):
gs[n(name)] = d(Type=n('ExtGState'), SMask=d(S=n('Luminosity'), G=group_ref,
BC=a(bc), TR=n('Identity')))
mask('Mask', shared_group)
mask('OpaqueBC', shared_group, (0,.5,1))
backgrounds = ((1,0,0), (0,1,0), (0,0,1), (0,.5,1))
for i, intent in enumerate(INTENTS):
mask('MaskRi'+str(i), group('/'+intent+' ri'))
mask('MaskGs'+str(i), group('/I'+str(i)+' gs'))
mask('MaskQ'+str(i), group('q /'+intent+' ri Q'))
mask('BC'+str(i), empty_group, backgrounds[i])
patterns = d()
def tiling(prefix='', colored=True, size=16):
content = prefix+'\n'+(paint if colored else '')+f'0 0 {size} {size} re f\n'
return stream(content, Type=n('Pattern'), PatternType=NumberObject(1), PaintType=NumberObject(1 if colored else 2),
TilingType=NumberObject(2), BBox=a((0,0,size,size)), XStep=NumberObject(size), YStep=NumberObject(size),
Resources=base if colored else d())
patterns[n('Tile')] = tiling()
patterns[n('U')] = tiling(colored=False, size=8)
patterns[n('ULarge')] = tiling(colored=False, size=1024)
for i, intent in enumerate(INTENTS):
patterns[n('TileRi'+str(i))] = tiling('/'+intent+' ri')
patterns[n('TileGs'+str(i))] = tiling('/I'+str(i)+' gs')
patterns[n('TileQ'+str(i))] = tiling('q /'+intent+' ri Q')
# Constant ICC axial function eliminates interpolation-position uncertainty.
function = writer._add_object(d(FunctionType=NumberObject(2), Domain=a((0,1)), C0=a(SAMPLE), C1=a(SAMPLE), N=NumberObject(1)))
shading = writer._add_object(d(ShadingType=NumberObject(2), ColorSpace=cs, Coords=a((0,0,WIDTH,0)),
Function=function, Extend=ArrayObject([BooleanObject(True),BooleanObject(True)])))
patterns[n('Shade')] = d(Type=n('Pattern'), PatternType=NumberObject(2), Shading=shading)
for i, intent in enumerate(INTENTS):
patterns[n('ShadeRi'+str(i))] = d(Type=n('Pattern'), PatternType=NumberObject(2), Shading=shading,
ExtGState=d(RI=n(intent)))
# A shared Form is invoked under distinct initial RI values. Its painting RI
# is always Absolute, which must not replace the pattern's stream-start RI.
form_resources = d(ColorSpace=colors, ExtGState=gs, Pattern=patterns)
xobjects = d()
for label, pattern_name in (('Tile','Tile'),('Shade','Shade')):
xobjects[n(label+'Form')] = stream('/AbsoluteColorimetric ri\n/Pattern cs /'+pattern_name+' scn 0 0 90 42 re f\n',
Type=n('XObject'), Subtype=n('Form'), BBox=a((0,0,90,42)), Resources=form_resources)
for i in range(4):
xobjects[n(label+'FormRi'+str(i))] = stream('/AbsoluteColorimetric ri\n/Pattern cs /'+pattern_name+'Ri'+str(i)+' scn 0 0 90 42 re f\n',
Type=n('XObject'), Subtype=n('Form'), BBox=a((0,0,90,42)), Resources=form_resources)
resources = d(ColorSpace=colors, ExtGState=gs, Pattern=patterns, XObject=xobjects,
Shading=d(A=shading), Font=d(F=font))
probes=[]
for group_index in range((len(CASES)+6)//7):
page=writer.add_blank_page(WIDTH,HEIGHT);page[n('Resources')]=resources
commands=[f'1 g 0 0 {WIDTH} {HEIGHT} re f',
f'0 g BT /F 18 Tf 24 818 Td (Soft masks and pattern state - {group_index+1}) Tj ET',
'0 g BT /F 9 Tf 24 799 Td (Synthetic ICC; expected intent comes from PDF state rules, colors from a direct CMM.) Tj ET']
for i,intent in enumerate(INTENTS):
commands.append(f'0 g BT /F 9 Tf {320+i*132} 771 Td ({intent}) Tj ET')
for row,case in enumerate(CASES[group_index*7:group_index*7+7]):
y=684-row*96
commands.append(f'0 g BT /F 10 Tf 24 {y+22} Td ({case}) Tj ET')
for column in range(4):
current=(2,0,2,1)[column] if case.endswith('-reuse') else column
other=(current+1)%4;expected=current;kind='icc';bc=None
x=320+column*132;rect=f'{x} {y} 90 42 re f'
start=['q','/'+INTENTS[current]+' ri'];body=[]
if case=='direct-icc-control': body=[paint+rect]
elif case.startswith('mask-'):
kind='luminosity-icc';mask_name='Mask'
if case=='mask-internal-ri':mask_name='MaskRi'+str(other);expected=other
elif case=='mask-internal-gs':mask_name='MaskGs'+str(other);expected=other
elif case=='mask-group-qQ':mask_name='MaskQ'+str(other)
elif case=='mask-BC-only':mask_name='BC'+str(column);bc=backgrounds[column];kind='luminosity-bc'
elif case=='mask-opaque-over-BC':mask_name='OpaqueBC'
body=['/'+mask_name+' gs']
if case=='mask-q-inner-none':body+=['q /NoMask gs','0 g '+rect,'Q'];kind='black'
elif case=='mask-Q-restores':body+=['q /NoMask gs Q','0 g '+rect]
elif case=='mask-none':body+=['/NoMask gs','0 g '+rect];kind='black'
else:body+=['0 g '+rect]
elif case.startswith('tiling-uncolored'):
if case.endswith('-gs'):start=['q','/I'+str(current)+' gs']
if 'stroke' in case:
pattern='ULarge' if case.endswith('-large') else 'U'
body=['1 0 0 rg','/PCS CS '+numbers(SAMPLE)+' /'+pattern+' SCN',
f'30 w {x} {y+21} m {x+90} {y+21} l S']
else:body=['/PCS cs '+numbers(SAMPLE)+' /U scn '+rect]
elif case.startswith('tiling-') or case.startswith('shading-'):
label='Tile' if case.startswith('tiling-') else 'Shade';pattern=label
if '-form-' in case:
form_name=label+'Form'
if case.endswith('-ri'):form_name+='Ri'+str(other);expected=other
body=[f'1 0 0 1 {x} {y} cm /'+form_name+' Do']
else:
expected=1
if case.endswith('-ri'):pattern+='Ri'+str(other);expected=other
elif case.endswith('-gs'):pattern+='Gs'+str(other);expected=other
elif case.endswith('-qQ'):pattern+='Q'+str(other)
body=['/Pattern cs /'+pattern+' scn '+rect]
elif case=='direct-shading-control':body=[f'{x} {y} 90 42 re W n','/A sh']
else:raise AssertionError(case)
sequence=start+body+['Q'];commands+=sequence
probes.append({'id':case+'-'+str(column),'case':case,'column':column,'page':group_index+1,
'callerIntentIndex':current,'callerIntent':INTENTS[current],
'expectedIntentIndex':expected,'expectedIntent':INTENTS[expected],
'oracle':kind,'components':list(SAMPLE),'backgroundRgb':list(bc) if bc else None,
'pointPt':[x+45,y+21],'commandSequence':sequence})
page[n('Contents')]=stream('\n'.join(commands)+'\n')
target=output/'intent-transparency.pdf';writer.write(target)
manifest={'schemaVersion':1,'file':target.name,'sha256':digest(target.read_bytes()),
'generatorSha256':digest(Path(__file__).read_bytes()),'pageCount':len(writer.pages),'pageSizePt':[WIDTH,HEIGHT],
'profile':{'file':SOURCE.name,'sha256':PROFILE_SHA,'size':len(profile),'origin':str(SOURCE.relative_to(ROOT))},
'sample':list(SAMPLE),'tolerance8Bit':4,'cases':list(CASES),'probes':probes,
'specification':{'url':'https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.4.pdf',
'printedPages':{'uncoloredForbiddenOperators':218,'tilingInitialState':223,'shadingInitialState':231,
'deviceRgbGray':377,'luminosityMask':440,'softMaskDictionary':446,'transparentPatterns':453}},
'luminosityOracle':{'weights':[.30,.59,.11],'foregroundRgb':[0,0,0],'pageBackgroundRgb':[255,255,255],
'formula':'round(255 - dot(weights, directCmmRgb8))',
'qualification':'DeviceRGB gray conversion is device-dependent; these are the PDF recommended weights. Intent dispatch is tested separately from that numerical convention.'}}
(output/'manifest.json').write_text(json.dumps(manifest,indent=2)+'\n')
(output/'README.md').write_text('''# Soft-mask and pattern rendering-intent probes
This self-authored 4-page PDF contains 108 declared pixel probes. The existing
984-byte distinct CMYK/Lab ICC profile is copied without alteration. Its four
intent outputs for CMYK (0, .75, .25, 0) have separated luminances; no PDF renderer
supplies the expected colors.
[Adobe PDF Reference 1.4](https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.4.pdf)
pp. 218, 223, 231 and 453 define pattern state. Colored tiling and shading patterns
start with their resource-owning page/Form stream's initial state. A Form is
reused under different initial intents, then changes its painting intent to
Absolute. Explicit pattern overrides and q/Q are separate controls. Uncolored
stencils contain no color operators or `ri`; their ICC base color is supplied by
the caller. Small/large uncolored strokes distinguish stroke from fill color.
Pages 440–446 define luminosity soft masks and their backdrop. The mask's RGB
group contains one opaque ICC rectangle, or no objects for the BC-only controls.
The direct CMM RGB result is reduced with the recommended .30/.59/.11 weights;
black over white has value 255 minus that luminosity. This device-dependent
formula is a declared test convention, not universal device calibration.
Run `tests/cmyk_lut/transparency.py --self-check --output NEW_DIRECTORY`, or pass
`--build-dir build --pdfium-library PATH/libpdfium.so --output NEW_DIRECTORY`.
The runner records all failures, validates the sandbox helper and library hash,
and judges PDFium and Poppler separately against the direct CMM. LittleCMS may
be shared with the renderers; this is not an independent CMM implementation or
general ICC conformance acceptance. The older 8-page intent fixture is unchanged.
''')
print(json.dumps({'file':str(target),'sha256':manifest['sha256'],'pages':len(writer.pages),'probes':len(probes)}))
if __name__=='__main__':
parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--output',type=Path,default=Path(__file__).parent/'intent-transparency')
generate(parser.parse_args().output)
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
"""Deterministic self-created links; no third-party document or font content."""
from pathlib import Path
import hashlib
import json
ROOT = Path(__file__).parent / 'link-borders'
ROOT.mkdir(exist_ok=True)
def stream(content, extra=''):
content = content.encode('ascii')
return f'<< /Length {len(content)} {extra} >>\nstream\n'.encode() + content + b'\nendstream'
def write(name, objects):
data = bytearray(b'%PDF-1.7\n%\xe2\xe3\xcf\xd3\n')
offsets = [0]
for i, value in enumerate(objects, 1):
offsets.append(len(data))
if isinstance(value, str): value = value.encode('ascii')
data += f'{i} 0 obj\n'.encode() + value + b'\nendobj\n'
xref = len(data)
data += f'xref\n0 {len(offsets)}\n0000000000 65535 f \n'.encode()
for offset in offsets[1:]: data += f'{offset:010d} 00000 n \n'.encode()
data += f'trailer\n<< /Size {len(offsets)} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n'.encode()
(ROOT / name).write_bytes(data)
return {'file': name, 'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest()}
CASES = [
('default', ''),
('solid-rgb', '/BS << /W 3 /S /S >> /C [0.8 0.1 0.2]'),
('dashed-border', '/Border [0 0 2 [6 3]] /C [0 0.2 0.8]'),
('dashed-bs-odd', '/BS << /W 2 /S /D /D [7 3 2] >> /C [0.1 0.5 0.2]'),
('dashed-default', '/BS << /W 2 /S /D >>'),
('underline', '/BS << /W 3 /S /U >> /C [0.6 0.1 0.8]'),
('bs-overrides-border', '/Border [9 9 12 [1 1]] /BS << /W 2 /S /S >> /C [0 0.3 0.7]'),
('zero-width', '/BS << /W 0 >>'),
('transparent', '/BS << /W 4 >> /C []'),
('hidden', '/BS << /W 4 >> /F 2'),
('no-view', '/BS << /W 4 >> /F 32'),
('print-flag-visible', '/BS << /W 2 >> /F 4'),
('gray', '/BS << /W 3 >> /C [0.5]'),
('cmyk', '/BS << /W 3 >> /C [1 0 0 0]'),
('rounded', '/Border [8 6 2] /C [0.6 0.3 0.1]'),
('beveled', '/BS << /W 3 /S /B >> /C [0.2 0.6 0.8]'),
('inset', '/BS << /W 3 /S /I >> /C [0.2 0.6 0.8]'),
('appearance-preserved', '/BS << /W 8 /S /D >> /C [1 0 0] /AP << /N 7 0 R >>'),
('empty-appearance-preserved', '/BS << /W 8 >> /AP << /N 8 0 R >>'),
('alpha', '/BS << /W 3 >> /C [0 0 1] /CA 0.5'),
]
# All pages share the same annotations, but their CropBox and Rotate differ.
# Rects straddle 512px tile boundaries at the evidence renderer's scale 2.
objects = [
'<< /Type /Catalog /Pages 2 0 R >>',
'<< /Type /Pages /Count 4 /Kids [3 0 R 4 0 R 5 0 R 6 0 R] >>',
'', '', '', '',
stream('0 0.8 0 rg 0 0 100 30 re f', '/Type /XObject /Subtype /Form /BBox [0 0 100 30] /Resources << >>'),
stream('', '/Type /XObject /Subtype /Form /BBox [0 0 100 30] /Resources << >>'),
]
expected = []
for index, (label, extra) in enumerate(CASES):
x = 40 + (index % 4) * 120
y = 50 + (index // 4) * 75
rect = [x, y, x + 100, y + 30]
objects.append(f'<< /Type /Annot /Subtype /Link /Rect [{" ".join(map(str, rect))}] '
f'/A << /S /URI /URI (https://example.org/{label}) >> {extra} >>')
expected.append({'name': label, 'rect': rect, 'has_border': label not in {'zero-width', 'transparent', 'hidden', 'no-view', 'empty-appearance-preserved'}})
annots = ' '.join(f'{i + 9} 0 R' for i in range(len(CASES)))
for page, rotation in enumerate([0, 90, 180, 270]):
objects[page + 2] = f'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 550 470] /CropBox [20 30 530 450] /Rotate {rotation} /Resources << >> /Annots [{annots}] >>'
records = [write('styles.pdf', objects)]
records[0]['pages'] = 4
records[0]['annotations'] = expected
records[0]['reference_limitations'] = ['Poppler ignores gray/CMYK border colors, rounded corners, bevel/inset, and alpha in its no-AP link fallback; assert these independently.', 'Saved normal AP must be preserved without adding a second border, even if Poppler adds one.']
for name, extra in [('unknown-style', '/BS << /S /Unknown >>'), ('no-zoom', '/F 8'), ('no-rotate', '/F 16'), ('invalid-dash', '/BS << /S /D /D [0 0] >>'), ('oversized-dash', '/BS << /S /D /D [' + '1 ' * 65 + '] >>'), ('invalid-color', '/C [0 1]'), ('invalid-ap', '/AP << /N 42 >>')]:
data = ['<< /Type /Catalog /Pages 2 0 R >>', '<< /Type /Pages /Count 1 /Kids [3 0 R] >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [4 0 R] >>',
f'<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] {extra} >>']
record = write(name + '.pdf', data)
if name in {'no-zoom', 'no-rotate'}:
record['expected'] = 'Valid annotation flag; rendering succeeds. Geometry coverage is in annotation-flags/flags.pdf.'
else:
record['render_error'] = 'E_PDF_ANNOT_UNSUPPORTED' if name == 'unknown-style' else 'E_LIMIT_EXCEEDED' if name == 'oversized-dash' else 'E_PDF_CORRUPT'
records.append(record)
retry = ['<< /Type /Catalog /Pages 2 0 R >>', '<< /Type /Pages /Count 2 /Kids [3 0 R 4 0 R] >>', '',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [5 0 R] >>']
for index in range(512):
retry.append('<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /BS << /S /D /D [' + '1 ' * 64 + '] >> >>')
retry.append('<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /BS << /S /Unknown >> >>')
retry[2] = '<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [' + ' '.join(f'{i} 0 R' for i in range(5, len(retry) + 1)) + '] >>'
record = write('retry-budget.pdf', retry)
record['expected'] = 'Forty failed page-0 decodes must not charge discarded appearances or prevent valid page-1 rendering.'
records.append(record)
(ROOT / 'manifest.json').write_text(json.dumps({'generator': 'generate_link_borders.py', 'license': 'Self-created test content; same license as DocView.', 'fixtures': records}, indent=2) + '\n')
+226
View File
@@ -0,0 +1,226 @@
#!/usr/bin/env python3
"""Generate self-authored ICC intent/state/cache probes without renderer goldens."""
import argparse
import hashlib
import itertools
import json
from pathlib import Path
import struct
from pypdf import PdfWriter
from pypdf.generic import (ArrayObject, ByteStringObject, DecodedStreamObject, DictionaryObject,
FloatObject, NameObject, NumberObject)
ROOT = Path(__file__).resolve().parents[3]
BASE = ROOT / 'tests/fixtures/pdf/cmyk-lut'
INTENTS = ('Perceptual', 'RelativeColorimetric', 'Saturation', 'AbsoluteColorimetric')
SAMPLE_BYTES = (51, 128, 204, 77)
SAMPLE = tuple(x/255 for x in SAMPLE_BYTES)
WIDTH, HEIGHT = 820, 800
CASES = ('default-relative', 'ri-vector', 'extgstate-ri', 'nested-q-inner', 'nested-Q-restore',
'form-inherit-shared', 'form-inherit-shared-gs', 'form-ri-override', 'form-gs-override', 'form-return-restore',
'image-inherit-shared-forward', 'image-inherit-shared-reverse', 'image-intent-override',
'image-inherit-shared-gs', 'image-override-return', 'indexed-vector', 'indexed-image', 'stroke', 'text', 'axial-shading',
'shading-pattern-inherit', 'shading-pattern-RI-override',
'type3-inherit-rectangle', 'type3-inherit-image', 'type3-ri-override')
def sha(data): return hashlib.sha256(data).hexdigest()
def array(values): return ArrayObject([FloatObject(x) for x in values])
def name(value): return NameObject('/'+value)
def dictionary(**values): return DictionaryObject({name(k):v for k,v in values.items()})
def fixed(values): return struct.pack('>'+'i'*len(values), *(round(v*65536) for v in values))
def operands(values): return ' '.join(f'{v:.10f}' for v in values)
def derived_model(tag, values):
c,m,y,k = values
if tag == 'A2B0': return (100-12*c-15*m-10*y-35*k,18*m-15*c,20*y-12*c)
if tag == 'A2B1': return (100-20*c-20*m-20*y-40*k,40*m-20*c-20*k,40*y-20*c-20*k)
if tag == 'A2B2': return (100-25*c-25*m-20*y-30*k,-40*m+20*c+20*k,35*y-20*m-15*k)
raise ValueError(tag)
def derived_profile(base):
# Reuse the existing input profile's v2 header, CLUT layout and attribution;
# add explicitly distinct self-authored intent tables and a non-D50 medium.
tags = {}
for i in range(struct.unpack_from('>I',base,128)[0]):
signature,offset,size=struct.unpack_from('>4sII',base,132+12*i)
tags[signature]=base[offset:offset+size]
tags[b'wtpt']=b'XYZ '+bytes(4)+fixed((.82,.86,.72))
for signature in ('A2B0','A2B1','A2B2'):
lut=bytearray(tags[b'A2B0'])
for i,values in enumerate(itertools.product((0,1),repeat=4)):
lightness,a,b=derived_model(signature,values)
struct.pack_into('>3H',lut,68+6*i,round(lightness/100*65280),round((a+128)*256),round((b+128)*256))
tags[signature.encode()]=bytes(lut)
description=b'DocView synthetic distinct rendering intent tables\0'
tags[b'desc']=b'desc'+bytes(4)+struct.pack('>I',len(description))+description+bytes(78)
header=bytearray(base[:128]);entries=bytearray();body=bytearray();offset=132+12*len(tags)
for signature,data in sorted(tags.items()):
entries+=signature+struct.pack('>II',offset+len(body),len(data))
body+=data+bytes((-len(data))%4)
result=header+struct.pack('>I',len(tags))+entries+body
result[:4]=struct.pack('>I',len(result))
return bytes(result)
def generate(output):
output.mkdir(parents=True,exist_ok=False)
base_spec=json.loads((BASE/'manifest.json').read_text())
base=(BASE/base_spec['profileFile']).read_bytes()
assert sha(base)==base_spec['profileSha256']
profiles={'original':base,'distinct':derived_profile(base)}
writer=PdfWriter();writer.pdf_header='%PDF-1.7'
writer.add_metadata({'/Title':'Rendering intent: explicit state, inheritance and cache',
'/Author':'DocView synthetic regression corpus'})
rows=[];profile_records={}
for profile_id,profile in profiles.items():
filename=profile_id+'-cmyk-lab.icc';(output/filename).write_bytes(profile)
profile_records[profile_id]={'file':filename,'sha256':sha(profile),'size':len(profile),
'origin':'byte-identical existing synthetic fixture' if profile_id=='original' else 'self-authored extension of the existing CLUT',
'mediaWhitePoint':[.9642,1,.8249] if profile_id=='original' else [.82,.86,.72],
'tables':['A2B0'] if profile_id=='original' else ['A2B0','A2B1','A2B2']}
stream=DecodedStreamObject();stream.set_data(profile)
stream.update(dictionary(N=NumberObject(4),Alternate=name('DeviceCMYK')))
space=ArrayObject([name('ICCBased'),writer._add_object(stream)])
indexed=ArrayObject([name('Indexed'),space,NumberObject(0),ByteStringObject(bytes(SAMPLE_BYTES))])
font=writer._add_object(dictionary(Type=name('Font'),Subtype=name('Type1'),BaseFont=name('Helvetica-Bold')))
gs=dictionary(**{'I'+str(i):dictionary(Type=name('ExtGState'),RI=name(intent)) for i,intent in enumerate(INTENTS)})
local_resources=dictionary(ColorSpace=dictionary(CS=space,IX=indexed),ExtGState=gs,Font=dictionary(F=font))
image=DecodedStreamObject();image.set_data(bytes(SAMPLE_BYTES))
image.update(dictionary(Type=name('XObject'),Subtype=name('Image'),Width=NumberObject(1),Height=NumberObject(1),
BitsPerComponent=NumberObject(8),ColorSpace=space))
shared_image=writer._add_object(image)
fonts=dictionary(F=font)
glyph_resources=dictionary(ColorSpace=dictionary(CS=space),XObject=dictionary(Shared=shared_image))
def type3_font(prefix='',image=False):
glyph=DecodedStreamObject()
painting='q 1000 0 0 1000 0 0 cm /Shared Do Q' if image else '/CS cs '+operands(SAMPLE)+' scn 0 0 1000 1000 re f'
glyph.set_data(('1000 0 d0\n'+prefix+'\n'+painting+'\n').encode())
encoding=dictionary(Type=name('Encoding'),Differences=ArrayObject([NumberObject(65),name('A')]))
return writer._add_object(dictionary(Type=name('Font'),Subtype=name('Type3'),FontBBox=array((0,0,1000,1000)),
FontMatrix=array((.001,0,0,.001,0,0)),CharProcs=dictionary(A=writer._add_object(glyph)),
Encoding=encoding,FirstChar=NumberObject(65),LastChar=NumberObject(65),Widths=array((1000,)),Resources=glyph_resources))
fonts[name('T3Rect')]=type3_font()
fonts[name('T3Image')]=type3_font(image=True)
for i,intent in enumerate(INTENTS):fonts[name('T3Override'+str(i))]=type3_font('/'+intent+' ri')
iximage=DecodedStreamObject();iximage.set_data(b'\0')
iximage.update(dictionary(Type=name('XObject'),Subtype=name('Image'),Width=NumberObject(1),Height=NumberObject(1),
BitsPerComponent=NumberObject(8),ColorSpace=indexed))
xobjects=dictionary(Shared=shared_image,Indexed=writer._add_object(iximage))
def form(prefix):
stream=DecodedStreamObject()
stream.set_data((prefix+'\n/CS cs '+operands(SAMPLE)+' scn 0 0 90 44 re f\n').encode())
stream.update(dictionary(Type=name('XObject'),Subtype=name('Form'),BBox=array((0,0,90,44)),Resources=local_resources))
return writer._add_object(stream)
xobjects[name('Inherited')]=form('')
for i,intent in enumerate(INTENTS):
copy=DecodedStreamObject();copy.set_data(bytes(SAMPLE_BYTES));copy.update(image)
copy[name('Intent')]=name(intent)
xobjects[name('Image'+str(i))]=writer._add_object(copy)
xobjects[name('Form'+str(i))]=form('/'+intent+' ri')
xobjects[name('FormGs'+str(i))]=form('/I'+str(i)+' gs')
shading_function=dictionary(FunctionType=NumberObject(2),Domain=array((0,1)),
C0=array((.1,.3,.6,.2)),C1=array((.5,.7,.9,.4)),N=NumberObject(1))
shading=dictionary(ShadingType=NumberObject(2),ColorSpace=space,Coords=array((0,0,90,0)),
Function=writer._add_object(shading_function))
from pypdf.generic import BooleanObject
shading[name('Extend')]=ArrayObject([BooleanObject(False),BooleanObject(False)])
wide_shading=DictionaryObject(shading);wide_shading[name('Coords')]=array((0,0,WIDTH,0))
wide_ref=writer._add_object(wide_shading)
patterns=dictionary(Inherited=dictionary(Type=name('Pattern'),PatternType=NumberObject(2),Shading=wide_ref))
for i,intent in enumerate(INTENTS):
patterns[name('P'+str(i))]=dictionary(Type=name('Pattern'),PatternType=NumberObject(2),Shading=wide_ref,
ExtGState=dictionary(RI=name(intent)))
resources=dictionary(ColorSpace=dictionary(CS=space,IX=indexed),ExtGState=gs,Font=fonts,
XObject=xobjects,Shading=dictionary(A=writer._add_object(shading)),Pattern=patterns)
for group in range((len(CASES)+7)//8):
page=writer.add_blank_page(WIDTH,HEIGHT);page[name('Resources')]=resources
commands=['0 g BT /F 17 Tf 28 762 Td (ICC rendering intent - '+profile_id+f' - {group+1}/{(len(CASES)+7)//8}) Tj ET']
commands+=['0 g BT /F 8 Tf 28 742 Td (Synthetic input profile; reference colors are computed independently by CMM, not copied from a renderer.) Tj ET']
for column,intent in enumerate(INTENTS):
commands.append(f'0 g BT /F 10 Tf {310+column*125} 716 Td ({intent}) Tj ET')
for local_row,case in enumerate(CASES[group*8:group*8+8]):
y=625-local_row*80
commands.append(f'0 g BT /F 10 Tf 28 {y+22} Td ({case}) Tj ET')
for column in range(4):
intent_index=3-column if case=='image-inherit-shared-reverse' else column
if case=='image-inherit-shared-gs': intent_index=(0,1,0,3)[column]
intent=INTENTS[intent_index];other=(intent_index+1)%4
x=310+column*125
start=['q'];body=[];expected=intent_index;point=(x+45,y+22);components=SAMPLE
if case=='default-relative':
# Start each cell at the page's untouched default. Other
# commands are isolated by q/Q, including all labels.
expected=1
elif case in ('extgstate-ri','image-inherit-shared-gs','form-inherit-shared-gs'): start+=['/I'+str(intent_index)+' gs']
else: start+=['/'+intent+' ri']
paint=f'/CS cs {operands(SAMPLE)} scn {x} {y} 90 44 re f'
if case in ('default-relative','ri-vector','extgstate-ri'): body=[paint]
elif case=='nested-q-inner': body=['q /'+INTENTS[other]+' ri',paint,'Q'];expected=other
elif case=='nested-Q-restore': body=['q /'+INTENTS[other]+' ri Q',paint]
elif case.startswith('form-'):
form_name='Inherited'
if case=='form-ri-override': form_name='Form'+str(other);expected=other
if case=='form-gs-override': form_name='FormGs'+str(other);expected=other
if case=='form-return-restore':
# Invoke the override at the origin, then
# paint with the caller's restored graphics state.
body=[f'/Form{other} Do',paint]
else: body=[f'q 1 0 0 1 {x} {y} cm /{form_name} Do Q']
elif case.startswith('image-') or case=='indexed-image':
image_name='Indexed' if case=='indexed-image' else 'Shared'
if case=='image-intent-override': image_name='Image'+str(other);expected=other
if case=='image-override-return': body=[f'/Image{other} Do',paint]
else: body=[f'q 90 0 0 44 {x} {y} cm /{image_name} Do Q']
elif case=='indexed-vector': body=[f'/IX cs 0 scn {x} {y} 90 44 re f']
elif case=='stroke': body=[f'/CS CS {operands(SAMPLE)} SCN 24 w {x} {y+22} m {x+90} {y+22} l S']
elif case=='text':
body=[f'/CS cs {operands(SAMPLE)} scn BT /F 64 Tf 1 0 0 1 {x} {y} Tm (H) Tj ET']
point=(x+8,y+29)
elif case=='axial-shading':
body=[f'q {x} {y} 90 44 re W n 1 0 0 1 {x} {y} cm /A sh Q']
components=(.3,.5,.75,.3)
elif case.startswith('shading-pattern-'):
pattern='Inherited'
if case=='shading-pattern-RI-override':pattern='P'+str(other);expected=other
body=[f'/Pattern cs /{pattern} scn {x} {y} 90 44 re f']
t=(x+45)/WIDTH;components=tuple(a+(b-a)*t for a,b in zip((.1,.3,.6,.2),(.5,.7,.9,.4)))
elif case.startswith('type3-'):
glyph_font='T3Image' if case=='type3-inherit-image' else 'T3Rect'
if case=='type3-ri-override':glyph_font='T3Override'+str(other);expected=other
body=[f'BT /{glyph_font} 44 Tf 1 0 0 1 {x} {y} Tm (A) Tj ET']
point=(x+22,y+22)
commands+=start+body+['Q']
rows.append({'page':len(writer.pages),'profile':profile_id,'case':case,'column':column,
'graphicsStateIntent':INTENTS[intent_index] if case!='default-relative' else 'default',
'expectedIntent':INTENTS[expected],'expectedIntentIndex':expected,'pointPt':list(point),
'components':list(components),'commandSequence':start+body+['Q'],
**({'shading':{'xStart':x if case=='axial-shading' else 0,'xEnd':x+90 if case=='axial-shading' else WIDTH,
'c0':[.1,.3,.6,.2],'c1':[.5,.7,.9,.4]}}
if case=='axial-shading' or case.startswith('shading-pattern-') else {})})
content=DecodedStreamObject();content.set_data(('\n'.join(commands)+'\n').encode())
page[name('Contents')]=writer._add_object(content)
pdf=output/'rendering-intents.pdf'
with pdf.open('wb') as target:writer.write(target)
manifest={'schemaVersion':1,'file':pdf.name,'sha256':sha(pdf.read_bytes()),'pageSizePt':[WIDTH,HEIGHT],
'pageCount':len(writer.pages),'profiles':profile_records,'baseProfileSha256':sha(base),'sampleBytes':list(SAMPLE_BYTES),
'intentOrder':list(INTENTS),'cases':list(CASES),'probes':rows,'tolerance8Bit':4,
'generatorSha256':sha(Path(__file__).read_bytes()),
'derivedProfileModels':{'A2B0':['100-12*C-15*M-10*Y-35*K','18*M-15*C','20*Y-12*C'],
'A2B1':['100-20*C-20*M-20*Y-40*K','40*M-20*C-20*K','40*Y-20*C-20*K'],
'A2B2':['100-25*C-25*M-20*Y-30*K','-40*M+20*C+20*K','35*Y-20*M-15*K']},
'references':['https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf',
'https://archive.color.org/files/icc32.pdf','https://www.littlecms.com/'],
'limits':['No measured press profile, human-approved golden, display calibration or broad ICC conformance claim.',
'Independent direct-CMM oracle can share LittleCMS code with PDF renderers; not a separate CMM implementation.',
'Text uses an interior point of the standard Helvetica-Bold H; axial samples account for raster pixel centers.']}
(output/'manifest.json').write_text(json.dumps(manifest,indent=2)+'\n')
print(json.dumps({'fileSha256':manifest['sha256'],'pages':len(writer.pages),'probes':len(rows)}))
if __name__=='__main__':
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--output',required=True,type=Path)
generate(parser.parse_args().output)
+68
View File
@@ -0,0 +1,68 @@
# Tagged-PDF boundary corpus
The 26 tagged PDFs and 4 context-only PDFs are self-authored. They contain
Standard-14 Helvetica text and vector paths, with no third-party document content.
Regenerate the deterministic files and hashes with:
```sh
python3 tests/fixtures/pdf/generate_headings.py
```
`manifest.json` records SHA-256, byte size, authored expectations and PDF-point
regions `[left, bottom, right, top]`. Regions follow the source placements,
font sizes and transforms; they are not copied from renderer output. None of the
tagged files has bookmarks, so an outline cannot conceal missing tag extraction.
`test_pdf::taggedBoundaryCorpus` checks every tagged file's hash, page count,
title, level, structure order, destination precision, fallback reason and bbox.
Exact targets must map inside the page and round-trip within 0.5 pt at scale 2
for user rotations 0, 90, 180 and 270 degrees. The PDFium drawing engine still
provides character boxes; a shared worker-only qpdf context now supplies the
source-qualified logical structure.
| Files | Authored condition and expected behavior |
| --- | --- |
| `transformed-form.pdf` | Page wrapper MCID plus Form-owned MCR. Exact heading in `[70,102,240,130]`. |
| `rotated-tags.pdf` | Rotate 90 and offset CropBox. H3 is drawn first but H1 precedes it in structure order; exact targets follow structure order. |
| `cross-page-structure.pdf` | One H1 has interleaved nested Span and direct MCR children on two pages. Page-local fragments preserve K order without mixing reused MCID 0. |
| `vector-heading.pdf` | H4 vector with ActualText but no glyph bbox. Title retained with page precision and a coordinate reason. |
| `form-only-structure.pdf` | Only the Form has StructParents. One exact H2, `Form only heading`, in `[50,125,190,147]`. This is now a positive extraction case. |
| `form-vector-mcid-collision.pdf` | Page vector heading and unrelated Form text both use MCID 0. Keep the heading title at page precision; never borrow Form paragraph bounds. |
| `named-property-rolemap.pdf` | Form BDC references a named property and a custom RoleMap name. Extract actual text without a supplied title. |
| `nested-form-matrix.pdf` | Nested Forms with a nonidentity Form Matrix and independent caller CTMs. Exact target uses PDFium page-space character boxes once. |
| `different-form-same-mcid.pdf` | Two uniquely positioned Forms reuse MCID 0, with reverse structure order. Keep separate exact headings in that order. |
| `ambiguous-form-matrix.pdf` | Different Forms share matrix and MCID signature. Use titles and explicit page precision instead of relying on enumeration order. |
| `repeated-form.pdf` | One source Form is invoked twice. Preserve the heading at page precision with a repeated-Form reason. |
| `unused-form-resource.pdf` | Uninvoked Form remains in Resources. It must not create an extra heading. |
| `inline-image-before-form.pdf` | Inline image precedes a used Form. Skip image pixels and retain the exact heading. |
| `cyclic-form.pdf`, `cyclic-rolemap.pdf`, `cyclic-parent.pdf`, `cyclic-children.pdf`, `cyclic-number-tree.pdf` | Explicit structure limitation, no fabricated destination. |
| `broken-mcr-page.pdf`, `broken-mcr-stream.pdf`, `annotation-owned-mcr.pdf`, `broken-graphics-stack.pdf`, `conflicting-parent-tree-owner.pdf` | Invalid or unsupported ownership/graphics relation. Explicit limitation, no borrowed exact text or position. |
| `stream-quota-at-limit.pdf`, `stream-quota-over-limit.pdf` | Compressed operator data expands to exactly 16 MiB or one byte more. The first succeeds; the second is limited, truncated and incomplete. |
| `bounded-heading-response.pdf` | 70 vector headings have long Japanese ActualText. Return a nonempty validated prefix within 512 KiB CBOR and mark the response incomplete. |
Context-only cases exercise the shared parser separately from PDFium:
- `context-deep-tree.pdf`: a depth failure must remain sticky on retries; the
valid later sibling must never become page zero.
- `context-warnings-32.pdf` and `context-warnings-33.pdf`: one diagnostic occurs
during initial parse and the remainder during lazy object reads. The 32-line
boundary succeeds; crossing it remains limited after a new operation begins.
- `context-warning-bytes.pdf`: one initial diagnostic exceeds 64 KiB. Opening
stops without emitting its contents.
The existing `../missing-first-page.pdf` separately checks that qpdf does not
repair `[null, page]` into a shortened page list before validation. This caught
the qpdf 12.4.1 `setMaxWarnings` startup side effect; diagnostics now use a bounded
private sink instead.
The production worker suite uses the real sandbox, IPC and font broker for
Form-only/nested exact destinations, ambiguous/repeated page fallbacks, quota,
partial response and cancellation. A temporary encrypted version checks wrong
password rejection, the same borrowed QFile and unchanged source bytes. Worker
cases compare original SHA-256 before and after. See the [recorded Linux
results](../../../results/pdf-structure/README.md).
Annotation-owned OBJR/StmOwn structures remain an explicit limitation. Repeated
or ambiguous Form instances deliberately retain page precision. These synthetic
cases do not establish native Windows behavior or general conformance for every
producer's tagged PDFs.
+63
View File
@@ -0,0 +1,63 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R /Fm1 8 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 37 >>
stream
q 1 0 0 1 40 100 cm /Fm0 Do /Fm1 Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [9 0 R 10 0 R] /ParentTree << /Kids [11 0 R] >> >>
endobj
7 0 obj
<< /Length 73 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Do not borrow first) Tj ET EMC
endstream
endobj
8 0 obj
<< /Length 74 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 1 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Do not borrow second) Tj ET EMC
endstream
endobj
9 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /T (First structure) /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
10 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /T (Second structure) /K << /Type /MCR /Pg 3 0 R /Stm 8 0 R /MCID 0 >> >>
endobj
11 0 obj
<< /Limits [0 1] /Nums [0 [9 0 R] 1 [10 0 R]] >>
endobj
xref
0 12
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000313 00000 n
0000000401 00000 n
0000000471 00000 n
0000000566 00000 n
0000000880 00000 n
0000001195 00000 n
0000001330 00000 n
0000001467 00000 n
trailer
<< /Size 12 /Root 1 0 R >>
startxref
1532
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 7 >>
stream
/Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 70 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Annotation-owned) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /StmOwn 3 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000359 00000 n
0000000429 00000 n
0000000516 00000 n
0000000816 00000 n
0000000945 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
998
%%EOF
File diff suppressed because one or more lines are too long
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 9 >>
stream
Q /Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 68 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Graphics stack) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000361 00000 n
0000000431 00000 n
0000000518 00000 n
0000000816 00000 n
0000000931 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
984
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 7 >>
stream
/Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 64 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Wrong page) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 7 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000359 00000 n
0000000429 00000 n
0000000516 00000 n
0000000810 00000 n
0000000925 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
978
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 7 >>
stream
/Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 66 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Wrong stream) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 3 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000359 00000 n
0000000429 00000 n
0000000516 00000 n
0000000812 00000 n
0000000927 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
980
%%EOF
@@ -0,0 +1,63 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R /Fm1 8 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 58 >>
stream
q 1 0 0 1 30 180 cm /Fm0 Do Q q 1 0 0 1 80 60 cm /Fm1 Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [9 0 R 10 0 R] /ParentTree << /Kids [11 0 R] >> >>
endobj
7 0 obj
<< /Length 65 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (First owner) Tj ET EMC
endstream
endobj
8 0 obj
<< /Length 66 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 1 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Second owner) Tj ET EMC
endstream
endobj
9 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 8 0 R /MCID 0 >> >>
endobj
10 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 8 0 R /MCID 0 >> >>
endobj
11 0 obj
<< /Limits [0 1] /Nums [0 [9 0 R] 1 [10 0 R]] >>
endobj
xref
0 12
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000313 00000 n
0000000422 00000 n
0000000492 00000 n
0000000587 00000 n
0000000893 00000 n
0000001200 00000 n
0000001315 00000 n
0000001431 00000 n
trailer
<< /Size 12 /Root 1 0 R >>
startxref
1496
%%EOF
+290
View File
@@ -0,0 +1,290 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 2 /Kids [3 0 R 70 0 R] >>
endobj
3 0 obj
<< /Type /Pages /Parent 2 0 R /Count 1 /Kids [4 0 R] >>
endobj
4 0 obj
<< /Type /Pages /Parent 3 0 R /Count 1 /Kids [5 0 R] >>
endobj
5 0 obj
<< /Type /Pages /Parent 4 0 R /Count 1 /Kids [6 0 R] >>
endobj
6 0 obj
<< /Type /Pages /Parent 5 0 R /Count 1 /Kids [7 0 R] >>
endobj
7 0 obj
<< /Type /Pages /Parent 6 0 R /Count 1 /Kids [8 0 R] >>
endobj
8 0 obj
<< /Type /Pages /Parent 7 0 R /Count 1 /Kids [9 0 R] >>
endobj
9 0 obj
<< /Type /Pages /Parent 8 0 R /Count 1 /Kids [10 0 R] >>
endobj
10 0 obj
<< /Type /Pages /Parent 9 0 R /Count 1 /Kids [11 0 R] >>
endobj
11 0 obj
<< /Type /Pages /Parent 10 0 R /Count 1 /Kids [12 0 R] >>
endobj
12 0 obj
<< /Type /Pages /Parent 11 0 R /Count 1 /Kids [13 0 R] >>
endobj
13 0 obj
<< /Type /Pages /Parent 12 0 R /Count 1 /Kids [14 0 R] >>
endobj
14 0 obj
<< /Type /Pages /Parent 13 0 R /Count 1 /Kids [15 0 R] >>
endobj
15 0 obj
<< /Type /Pages /Parent 14 0 R /Count 1 /Kids [16 0 R] >>
endobj
16 0 obj
<< /Type /Pages /Parent 15 0 R /Count 1 /Kids [17 0 R] >>
endobj
17 0 obj
<< /Type /Pages /Parent 16 0 R /Count 1 /Kids [18 0 R] >>
endobj
18 0 obj
<< /Type /Pages /Parent 17 0 R /Count 1 /Kids [19 0 R] >>
endobj
19 0 obj
<< /Type /Pages /Parent 18 0 R /Count 1 /Kids [20 0 R] >>
endobj
20 0 obj
<< /Type /Pages /Parent 19 0 R /Count 1 /Kids [21 0 R] >>
endobj
21 0 obj
<< /Type /Pages /Parent 20 0 R /Count 1 /Kids [22 0 R] >>
endobj
22 0 obj
<< /Type /Pages /Parent 21 0 R /Count 1 /Kids [23 0 R] >>
endobj
23 0 obj
<< /Type /Pages /Parent 22 0 R /Count 1 /Kids [24 0 R] >>
endobj
24 0 obj
<< /Type /Pages /Parent 23 0 R /Count 1 /Kids [25 0 R] >>
endobj
25 0 obj
<< /Type /Pages /Parent 24 0 R /Count 1 /Kids [26 0 R] >>
endobj
26 0 obj
<< /Type /Pages /Parent 25 0 R /Count 1 /Kids [27 0 R] >>
endobj
27 0 obj
<< /Type /Pages /Parent 26 0 R /Count 1 /Kids [28 0 R] >>
endobj
28 0 obj
<< /Type /Pages /Parent 27 0 R /Count 1 /Kids [29 0 R] >>
endobj
29 0 obj
<< /Type /Pages /Parent 28 0 R /Count 1 /Kids [30 0 R] >>
endobj
30 0 obj
<< /Type /Pages /Parent 29 0 R /Count 1 /Kids [31 0 R] >>
endobj
31 0 obj
<< /Type /Pages /Parent 30 0 R /Count 1 /Kids [32 0 R] >>
endobj
32 0 obj
<< /Type /Pages /Parent 31 0 R /Count 1 /Kids [33 0 R] >>
endobj
33 0 obj
<< /Type /Pages /Parent 32 0 R /Count 1 /Kids [34 0 R] >>
endobj
34 0 obj
<< /Type /Pages /Parent 33 0 R /Count 1 /Kids [35 0 R] >>
endobj
35 0 obj
<< /Type /Pages /Parent 34 0 R /Count 1 /Kids [36 0 R] >>
endobj
36 0 obj
<< /Type /Pages /Parent 35 0 R /Count 1 /Kids [37 0 R] >>
endobj
37 0 obj
<< /Type /Pages /Parent 36 0 R /Count 1 /Kids [38 0 R] >>
endobj
38 0 obj
<< /Type /Pages /Parent 37 0 R /Count 1 /Kids [39 0 R] >>
endobj
39 0 obj
<< /Type /Pages /Parent 38 0 R /Count 1 /Kids [40 0 R] >>
endobj
40 0 obj
<< /Type /Pages /Parent 39 0 R /Count 1 /Kids [41 0 R] >>
endobj
41 0 obj
<< /Type /Pages /Parent 40 0 R /Count 1 /Kids [42 0 R] >>
endobj
42 0 obj
<< /Type /Pages /Parent 41 0 R /Count 1 /Kids [43 0 R] >>
endobj
43 0 obj
<< /Type /Pages /Parent 42 0 R /Count 1 /Kids [44 0 R] >>
endobj
44 0 obj
<< /Type /Pages /Parent 43 0 R /Count 1 /Kids [45 0 R] >>
endobj
45 0 obj
<< /Type /Pages /Parent 44 0 R /Count 1 /Kids [46 0 R] >>
endobj
46 0 obj
<< /Type /Pages /Parent 45 0 R /Count 1 /Kids [47 0 R] >>
endobj
47 0 obj
<< /Type /Pages /Parent 46 0 R /Count 1 /Kids [48 0 R] >>
endobj
48 0 obj
<< /Type /Pages /Parent 47 0 R /Count 1 /Kids [49 0 R] >>
endobj
49 0 obj
<< /Type /Pages /Parent 48 0 R /Count 1 /Kids [50 0 R] >>
endobj
50 0 obj
<< /Type /Pages /Parent 49 0 R /Count 1 /Kids [51 0 R] >>
endobj
51 0 obj
<< /Type /Pages /Parent 50 0 R /Count 1 /Kids [52 0 R] >>
endobj
52 0 obj
<< /Type /Pages /Parent 51 0 R /Count 1 /Kids [53 0 R] >>
endobj
53 0 obj
<< /Type /Pages /Parent 52 0 R /Count 1 /Kids [54 0 R] >>
endobj
54 0 obj
<< /Type /Pages /Parent 53 0 R /Count 1 /Kids [55 0 R] >>
endobj
55 0 obj
<< /Type /Pages /Parent 54 0 R /Count 1 /Kids [56 0 R] >>
endobj
56 0 obj
<< /Type /Pages /Parent 55 0 R /Count 1 /Kids [57 0 R] >>
endobj
57 0 obj
<< /Type /Pages /Parent 56 0 R /Count 1 /Kids [58 0 R] >>
endobj
58 0 obj
<< /Type /Pages /Parent 57 0 R /Count 1 /Kids [59 0 R] >>
endobj
59 0 obj
<< /Type /Pages /Parent 58 0 R /Count 1 /Kids [60 0 R] >>
endobj
60 0 obj
<< /Type /Pages /Parent 59 0 R /Count 1 /Kids [61 0 R] >>
endobj
61 0 obj
<< /Type /Pages /Parent 60 0 R /Count 1 /Kids [62 0 R] >>
endobj
62 0 obj
<< /Type /Pages /Parent 61 0 R /Count 1 /Kids [63 0 R] >>
endobj
63 0 obj
<< /Type /Pages /Parent 62 0 R /Count 1 /Kids [64 0 R] >>
endobj
64 0 obj
<< /Type /Pages /Parent 63 0 R /Count 1 /Kids [65 0 R] >>
endobj
65 0 obj
<< /Type /Pages /Parent 64 0 R /Count 1 /Kids [66 0 R] >>
endobj
66 0 obj
<< /Type /Pages /Parent 65 0 R /Count 1 /Kids [67 0 R] >>
endobj
67 0 obj
<< /Type /Pages /Parent 66 0 R /Count 1 /Kids [68 0 R] >>
endobj
68 0 obj
<< /Type /Pages /Parent 67 0 R /Count 1 /Kids [69 0 R] >>
endobj
69 0 obj
<< /Type /Page /Parent 68 0 R /MediaBox [0 0 100 100] /Resources << >> >>
endobj
70 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Resources << >> >>
endobj
xref
0 71
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000128 00000 n
0000000199 00000 n
0000000270 00000 n
0000000341 00000 n
0000000412 00000 n
0000000483 00000 n
0000000554 00000 n
0000000626 00000 n
0000000699 00000 n
0000000773 00000 n
0000000847 00000 n
0000000921 00000 n
0000000995 00000 n
0000001069 00000 n
0000001143 00000 n
0000001217 00000 n
0000001291 00000 n
0000001365 00000 n
0000001439 00000 n
0000001513 00000 n
0000001587 00000 n
0000001661 00000 n
0000001735 00000 n
0000001809 00000 n
0000001883 00000 n
0000001957 00000 n
0000002031 00000 n
0000002105 00000 n
0000002179 00000 n
0000002253 00000 n
0000002327 00000 n
0000002401 00000 n
0000002475 00000 n
0000002549 00000 n
0000002623 00000 n
0000002697 00000 n
0000002771 00000 n
0000002845 00000 n
0000002919 00000 n
0000002993 00000 n
0000003067 00000 n
0000003141 00000 n
0000003215 00000 n
0000003289 00000 n
0000003363 00000 n
0000003437 00000 n
0000003511 00000 n
0000003585 00000 n
0000003659 00000 n
0000003733 00000 n
0000003807 00000 n
0000003881 00000 n
0000003955 00000 n
0000004029 00000 n
0000004103 00000 n
0000004177 00000 n
0000004251 00000 n
0000004325 00000 n
0000004399 00000 n
0000004473 00000 n
0000004547 00000 n
0000004621 00000 n
0000004695 00000 n
0000004769 00000 n
0000004843 00000 n
0000004917 00000 n
0000004991 00000 n
0000005081 00000 n
trailer
<< /Size 71 /Root 1 0 R >>
startxref
5170
%%EOF
File diff suppressed because one or more lines are too long
+146
View File
@@ -0,0 +1,146 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /Duplicate 1 /Duplicate 2 /Probe [4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R] >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> >>
endobj
4 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
5 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
6 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
7 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
8 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
9 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
10 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
11 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
12 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
13 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
14 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
15 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
16 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
17 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
18 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
19 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
20 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
21 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
22 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
23 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
24 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
25 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
26 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
27 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
28 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
29 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
30 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
31 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
32 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
33 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
34 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
xref
0 35
0000000000 65535 f
0000000015 00000 n
0000000310 00000 n
0000000367 00000 n
0000000455 00000 n
0000000502 00000 n
0000000549 00000 n
0000000596 00000 n
0000000643 00000 n
0000000690 00000 n
0000000737 00000 n
0000000785 00000 n
0000000833 00000 n
0000000881 00000 n
0000000929 00000 n
0000000977 00000 n
0000001025 00000 n
0000001073 00000 n
0000001121 00000 n
0000001169 00000 n
0000001217 00000 n
0000001265 00000 n
0000001313 00000 n
0000001361 00000 n
0000001409 00000 n
0000001457 00000 n
0000001505 00000 n
0000001553 00000 n
0000001601 00000 n
0000001649 00000 n
0000001697 00000 n
0000001745 00000 n
0000001793 00000 n
0000001841 00000 n
0000001889 00000 n
trailer
<< /Size 35 /Root 1 0 R >>
startxref
1937
%%EOF
+150
View File
@@ -0,0 +1,150 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /Duplicate 1 /Duplicate 2 /Probe [4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R] >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> >>
endobj
4 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
5 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
6 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
7 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
8 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
9 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
10 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
11 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
12 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
13 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
14 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
15 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
16 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
17 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
18 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
19 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
20 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
21 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
22 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
23 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
24 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
25 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
26 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
27 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
28 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
29 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
30 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
31 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
32 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
33 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
34 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
35 0 obj
<< /Duplicate 1 /Duplicate 2 >>
endobj
xref
0 36
0000000000 65535 f
0000000015 00000 n
0000000317 00000 n
0000000374 00000 n
0000000462 00000 n
0000000509 00000 n
0000000556 00000 n
0000000603 00000 n
0000000650 00000 n
0000000697 00000 n
0000000744 00000 n
0000000792 00000 n
0000000840 00000 n
0000000888 00000 n
0000000936 00000 n
0000000984 00000 n
0000001032 00000 n
0000001080 00000 n
0000001128 00000 n
0000001176 00000 n
0000001224 00000 n
0000001272 00000 n
0000001320 00000 n
0000001368 00000 n
0000001416 00000 n
0000001464 00000 n
0000001512 00000 n
0000001560 00000 n
0000001608 00000 n
0000001656 00000 n
0000001704 00000 n
0000001752 00000 n
0000001800 00000 n
0000001848 00000 n
0000001896 00000 n
0000001944 00000 n
trailer
<< /Size 36 /Root 1 0 R >>
startxref
1992
%%EOF
+75
View File
@@ -0,0 +1,75 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 8 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 2 /Kids [3 0 R 4 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 0 /Resources << /Font << /F1 7 0 R >> >> /Contents 5 0 R >>
endobj
4 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 1 /Resources << /Font << /F1 7 0 R >> >> /Contents 6 0 R >>
endobj
5 0 obj
<< /Length 134 >>
stream
/Span <</MCID 0>> BDC BT /F1 16 Tf 40 60 Td (Across page one) Tj ET EMC
/H1 <</MCID 1>> BDC BT /F1 16 Tf 170 60 Td ( middle) Tj ET EMC
endstream
endobj
6 0 obj
<< /Length 219 >>
stream
/P <</MCID 2>> BDC BT /F1 16 Tf 40 120 Td (Unrelated paragraph) Tj ET EMC
/H2 <</MCID 1>> BDC BT /F1 16 Tf 40 160 Td (Following heading) Tj ET EMC
/Span <</MCID 0>> BDC BT /F1 16 Tf 40 210 Td (Across page two) Tj ET EMC
endstream
endobj
7 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
8 0 obj
<< /Type /StructTreeRoot /K [9 0 R] /ParentTree << /Nums [0 [12 0 R 10 0 R] 1 [13 0 R 11 0 R 14 0 R]] >> /ParentTreeNextKey 2 >>
endobj
9 0 obj
<< /Type /StructElem /S /Sect /P 8 0 R /K [10 0 R 11 0 R 14 0 R] >>
endobj
10 0 obj
<< /Type /StructElem /S /H1 /P 9 0 R /T (Across pages) /K [12 0 R << /Type /MCR /Pg 3 0 R /MCID 1 >> 13 0 R] >>
endobj
11 0 obj
<< /Type /StructElem /S /H2 /P 9 0 R /Pg 4 0 R /K 1 >>
endobj
12 0 obj
<< /Type /StructElem /S /Span /P 10 0 R /Pg 3 0 R /K 0 >>
endobj
13 0 obj
<< /Type /StructElem /S /Span /P 10 0 R /Pg 4 0 R /K 0 >>
endobj
14 0 obj
<< /Type /StructElem /S /P /P 9 0 R /Pg 4 0 R /K 2 >>
endobj
xref
0 15
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000178 00000 n
0000000321 00000 n
0000000464 00000 n
0000000650 00000 n
0000000921 00000 n
0000000991 00000 n
0000001135 00000 n
0000001218 00000 n
0000001346 00000 n
0000001417 00000 n
0000001491 00000 n
0000001565 00000 n
trailer
<< /Size 15 /Root 1 0 R >>
startxref
1635
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 7 >>
stream
/Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 65 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Child cycle) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K 8 0 R >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000359 00000 n
0000000429 00000 n
0000000516 00000 n
0000000811 00000 n
0000000885 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
938
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 7 >>
stream
/Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 7 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/Fm0 Do
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000359 00000 n
0000000429 00000 n
0000000516 00000 n
0000000752 00000 n
0000000867 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
920
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 7 >>
stream
/Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 65 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Number tree) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Kids [9 0 R] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000359 00000 n
0000000429 00000 n
0000000516 00000 n
0000000811 00000 n
0000000926 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
975
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 7 >>
stream
/Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 66 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Parent cycle) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 8 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000359 00000 n
0000000429 00000 n
0000000516 00000 n
0000000812 00000 n
0000000927 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
980
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 7 >>
stream
/Fm0 Do
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> /RoleMap << /Foo /Bar /Bar /Foo >> >>
endobj
7 0 obj
<< /Length 69 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Hidden by cycle) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /Foo /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000359 00000 n
0000000429 00000 n
0000000550 00000 n
0000000849 00000 n
0000000965 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
1018
%%EOF
@@ -0,0 +1,63 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R /Fm1 8 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 58 >>
stream
q 1 0 0 1 30 180 cm /Fm0 Do Q q 1 0 0 1 80 60 cm /Fm1 Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [10 0 R 9 0 R] /ParentTree << /Kids [11 0 R] >> >>
endobj
7 0 obj
<< /Length 64 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (First form) Tj ET EMC
endstream
endobj
8 0 obj
<< /Length 65 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 1 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Second form) Tj ET EMC
endstream
endobj
9 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
10 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 8 0 R /MCID 0 >> >>
endobj
11 0 obj
<< /Limits [0 1] /Nums [0 [9 0 R] 1 [10 0 R]] >>
endobj
xref
0 12
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000313 00000 n
0000000422 00000 n
0000000492 00000 n
0000000587 00000 n
0000000892 00000 n
0000001198 00000 n
0000001313 00000 n
0000001429 00000 n
trailer
<< /Size 12 /Root 1 0 R >>
startxref
1494
%%EOF
+48
View File
@@ -0,0 +1,48 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 7 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /Resources << /XObject << /Fm 6 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 28 >>
stream
q 1 0 0 1 40 100 cm /Fm Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Length 71 /Type /XObject /Subtype /Form /BBox [0 0 200 80] /StructParents 0 /Resources << /Font << /F1 5 0 R >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 16 Tf 10 30 Td (Form only heading) Tj ET EMC
endstream
endobj
7 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Nums [0 [8 0 R]] >> /ParentTreeNextKey 1 >>
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 7 0 R /Pg 3 0 R /T (Form only heading) /K << /Type /MCR /Pg 3 0 R /Stm 6 0 R /MCID 0 >> >>
endobj
xref
0 9
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000301 00000 n
0000000380 00000 n
0000000450 00000 n
0000000676 00000 n
0000000787 00000 n
trailer
<< /Size 9 /Root 1 0 R >>
startxref
924
%%EOF
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 7 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 0 /Resources << /XObject << /Fm 6 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 80 >>
stream
/H1 <</MCID 0>> BDC 0 0 1 rg 40 180 180 20 re f EMC q 1 0 0 1 40 100 cm /Fm Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Length 77 /Type /XObject /Subtype /Form /BBox [0 0 240 80] /StructParents 1 /Resources << /Font << /F1 5 0 R >> >> >>
stream
/P <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Unrelated Form paragraph) Tj ET EMC
endstream
endobj
7 0 obj
<< /Type /StructTreeRoot /K [8 0 R 9 0 R] /ParentTree << /Nums [0 [8 0 R] 1 [9 0 R]] >> /ParentTreeNextKey 2 >>
endobj
8 0 obj
<< /Type /StructElem /S /H1 /P 7 0 R /Pg 3 0 R /T (Page vector heading) /K 0 >>
endobj
9 0 obj
<< /Type /StructElem /S /P /P 7 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 6 0 R /MCID 0 >> >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000318 00000 n
0000000449 00000 n
0000000519 00000 n
0000000751 00000 n
0000000878 00000 n
0000000973 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
1086
%%EOF
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 64 >>
stream
q 1 0 0 1 40 100 cm BI /W 1 /H 1 /BPC 8 /CS /G ID X EI /Fm0 Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 65 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (After image) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000417 00000 n
0000000487 00000 n
0000000574 00000 n
0000000869 00000 n
0000000984 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
1037
%%EOF
+537
View File
@@ -0,0 +1,537 @@
{
"origin": "Self-created deterministic PDF syntax, Helvetica Standard-14 text and vector paths; no third-party document content.",
"generator": "../generate_headings.py",
"documents": [
{
"file": "transformed-form.pdf",
"bytes": 1236,
"sha256": "55b6ee047e70b0dc463ac4b59ab3464bbb45a4cab12521ba23de41bc95197b98",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Form heading",
"level": 2,
"precision": "exact",
"text_region_pt": [
70,
102,
240,
130
]
}
],
"form_matrix": [
1.5,
0,
0,
1.25,
55,
70
],
"local_baseline": [
10,
30
]
}
},
{
"file": "rotated-tags.pdf",
"bytes": 1095,
"sha256": "8f2b850785b13d0de9ada1e8e31b15e6fe381f444eaaa1397acda481d1612c1e",
"expected": {
"pages": 1,
"crop_box": [
20,
30,
280,
230
],
"rotation": 90,
"headings": [
{
"page": 0,
"title": "Rotated first",
"level": 1,
"precision": "exact",
"text_region_pt": [
50,
168,
170,
190
]
},
{
"page": 0,
"title": "Rotated second",
"level": 3,
"precision": "exact",
"text_region_pt": [
60,
78,
180,
96
]
}
],
"order": "structure order, intentionally different from content-stream draw order"
}
},
{
"file": "cross-page-structure.pdf",
"bytes": 2001,
"sha256": "52ec19216440feebdb80b2d25339282b82b219a017fdf7c057c618f92db89373",
"expected": {
"pages": 2,
"headings": [
{
"page": 0,
"title": "Across page one middle",
"level": 1,
"precision": "exact",
"text_region_pt": [
40,
55,
230,
78
]
},
{
"page": 1,
"title": "Across page two",
"level": 1,
"precision": "exact",
"text_region_pt": [
40,
205,
170,
228
]
},
{
"page": 1,
"title": "Following heading",
"level": 2,
"precision": "exact",
"text_region_pt": [
40,
155,
180,
178
]
}
],
"scope": "One heading spans two page-local Span elements with an interleaved direct MCR; MCID 0 is reused independently on both pages. Results are page-local fragments."
}
},
{
"file": "vector-heading.pdf",
"bytes": 787,
"sha256": "0083680fe3b8d27525b4e9b442155444095b19a9f3d7921696531be12dcf2175",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Vector section",
"level": 4,
"precision": "page",
"reason_contains": "座標"
}
],
"drawn_region_pt": [
40,
180,
190,
200
],
"fallback": "No text glyph bounding box is available for the marked vector path."
}
},
{
"file": "form-only-structure.pdf",
"bytes": 1167,
"sha256": "4ad6e541fe9df9d656ad78eb477a751eafa22f9147a501dfed68b4fd3ef6e235",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Form only heading",
"level": 2,
"precision": "exact",
"text_region_pt": [
50,
125,
190,
147
]
}
],
"scope": "Form StructParents and source-qualified MCR; no page StructParents."
}
},
{
"file": "form-vector-mcid-collision.pdf",
"bytes": 1352,
"sha256": "bc37979a4cb8a96872fb43c75b183aa82ac64c5934844e8233b79e7910640128",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Page vector heading",
"level": 1,
"precision": "page",
"reason_contains": "MCID"
}
],
"fallback": "MCID 0 names a page vector and unrelated Form text. Non-text page objects must participate in stream collision detection."
}
},
{
"file": "named-property-rolemap.pdf",
"bytes": 1321,
"sha256": "2da7e79e65977378ce7f2114bbfa3df1a23181c633cf7988d533388b4e89f142",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Named property heading",
"level": 3,
"precision": "exact",
"text_region_pt": [
50,
127,
190,
142
]
}
]
}
},
{
"file": "nested-form-matrix.pdf",
"bytes": 1791,
"sha256": "8d872ae76bbd8164b34a4fb9d1a0b2cc73f900f5b2349f5486b10079b7442084",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Nested heading",
"level": 2,
"precision": "exact",
"text_region_pt": [
82,
161,
245,
181
]
}
]
}
},
{
"file": "different-form-same-mcid.pdf",
"bytes": 1800,
"sha256": "d337fb72b0434370a15b1d8470dca33e5492fe4cc01f352506a947fb135cfcf5",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Second form",
"level": 2,
"precision": "exact",
"text_region_pt": [
90,
87,
170,
102
]
},
{
"page": 0,
"title": "First form",
"level": 2,
"precision": "exact",
"text_region_pt": [
40,
207,
105,
222
]
}
]
}
},
{
"file": "ambiguous-form-matrix.pdf",
"bytes": 1838,
"sha256": "25103b29c1fc392378f69e66f480e480868d1d85f764f431bb6002cba3f213ce",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "First structure",
"level": 2,
"precision": "page",
"reason_contains": "一意"
},
{
"page": 0,
"title": "Second structure",
"level": 2,
"precision": "page",
"reason_contains": "一意"
}
]
}
},
{
"file": "repeated-form.pdf",
"bytes": 1302,
"sha256": "d05f07ddedd2a045f3f3f66bc554fad6fb2c651828080472130f139783e9596f",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Repeated heading",
"level": 2,
"precision": "page",
"reason_contains": "複数回"
}
]
}
},
{
"file": "unused-form-resource.pdf",
"bytes": 1776,
"sha256": "c203b8c8bf3afadd76e51692390c81d866fba0ce56b438a7b6613bd75f2bcbad",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "Used heading",
"level": 2,
"precision": "exact",
"text_region_pt": [
50,
127,
140,
142
]
}
]
}
},
{
"file": "inline-image-before-form.pdf",
"bytes": 1303,
"sha256": "3fc737049b0a92d72b813ae5d6455c4bb51da08f561371374b3acc99f7356ae5",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "After image",
"level": 2,
"precision": "exact",
"text_region_pt": [
50,
127,
125,
142
]
}
]
}
},
{
"file": "cyclic-form.pdf",
"bytes": 1185,
"sha256": "3143516932a8c9b4355325d251e0cc5d1af77edd368ad915c0bf6990643cf74a",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "cyclic-rolemap.pdf",
"bytes": 1284,
"sha256": "aa0772a34f4abd035e2e7d4aa6438a49774b791b9520d3269cffa52b1575a2fc",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "cyclic-parent.pdf",
"bytes": 1245,
"sha256": "46e4ac7e96e372b05f35718b675552f58ad618887e53ba31a044da748edd1036",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "cyclic-children.pdf",
"bytes": 1203,
"sha256": "7c9f49595fa3001b2c35c7eaf389d57dc2d6d7c910ef36d35ef0810c8e0d7935",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "broken-mcr-page.pdf",
"bytes": 1243,
"sha256": "aa1722f9ec4e4d5affd531e40a58c76be1ecfb60e4b2b7d20bbab53e459a4abd",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "broken-mcr-stream.pdf",
"bytes": 1245,
"sha256": "c2c20b93bf307df69ab5a5b962f2f399d761a987e372707b830be7ae12839596",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "annotation-owned-mcr.pdf",
"bytes": 1263,
"sha256": "282612ae3bfecdc233e6818ee4a680f3e4541f060979443952b595c9d76943cc",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "broken-graphics-stack.pdf",
"bytes": 1249,
"sha256": "ac27fe4c8e166a4f241737578b9e846df685b83b85cc8d9447f7c33203d66c15",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "cyclic-number-tree.pdf",
"bytes": 1240,
"sha256": "e1adb2ebb053be176f746b89b8e24946b1c9a86cbe05421f7691e49787cbc541",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "conflicting-parent-tree-owner.pdf",
"bytes": 1802,
"sha256": "6def473a2db3cef07e481de5ae6a9ae0837d60da1ceb66ffaa47e250de0b6876",
"expected": {
"pages": 1,
"headings": [],
"limited": true
}
},
{
"file": "stream-quota-at-limit.pdf",
"bytes": 17615,
"sha256": "40a56f12e42fe67ce3b656027a7fc4348a5cb34d5ce8f0f38350567b2e178924",
"expected": {
"pages": 1,
"headings": [
{
"page": 0,
"title": "At stream limit",
"level": 2,
"precision": "exact",
"text_region_pt": [
50,
127,
140,
142
]
}
]
}
},
{
"file": "stream-quota-over-limit.pdf",
"bytes": 17617,
"sha256": "80cf057acd5c6c2454fb6cba20100559bb892e0828a23d3ce50405b5477fb735",
"expected": {
"pages": 1,
"headings": [],
"limited": true,
"truncated": true
}
},
{
"file": "bounded-heading-response.pdf",
"bytes": 1157442,
"sha256": "820ea69c56ac33587114886aded122e9d7705e0ffdccaa6eefbb81ab4a05f6ce",
"expected": {
"pages": 1,
"headings": [],
"response_limited": true
}
}
],
"context_documents": [
{
"file": "context-deep-tree.pdf",
"bytes": 6656,
"sha256": "66dc1bc3c5fd062334fddc9e2f0ef420b168e0ed44397bb2374c6b35695d86de",
"expected": {
"scope": "Context-only regression: after a depth failure, the second page must never be assigned index zero."
}
},
{
"file": "context-warnings-32.pdf",
"bytes": 2703,
"sha256": "1ed5ad72f3054844c158ffff87977616caaca63cbb864a50b1c9be96ac1a5ec6",
"expected": {
"scope": "Context-only cumulative diagnostic limit, starting in initial parse; warning bodies must never reach stdout/stderr.",
"accepted": true
}
},
{
"file": "context-warnings-33.pdf",
"bytes": 2778,
"sha256": "29e105aa8c78d8b6a0ab1a5d7c7f99663abd952f1657c0c17c43ab24406822a1",
"expected": {
"scope": "Context-only cumulative diagnostic limit, starting in initial parse; warning bodies must never reach stdout/stderr.",
"accepted": false
}
},
{
"file": "context-warning-bytes.pdf",
"bytes": 131435,
"sha256": "42c792b2fa035674a22bde94fe681bc89406e3f015be7e32f49d3a3410364319",
"expected": {
"scope": "Context-only diagnostic byte limit during initial parse; no warning text is retained or emitted.",
"accepted": false
}
}
]
}
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 29 >>
stream
q 1 0 0 1 40 100 cm /Fm0 Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> /RoleMap << /Section /H3 >> >>
endobj
7 0 obj
<< /Length 86 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/Section /HeadingProperty BDC BT /F1 12 Tf 10 30 Td (Named property heading) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /Section /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000382 00000 n
0000000452 00000 n
0000000566 00000 n
0000000882 00000 n
0000001002 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
1055
%%EOF
+63
View File
@@ -0,0 +1,63 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R /Fm1 8 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 29 >>
stream
q 1 0 0 1 40 100 cm /Fm0 Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [9 0 R 10 0 R] /ParentTree << /Kids [11 0 R] >> >>
endobj
7 0 obj
<< /Length 33 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> /Matrix [1.2 0 0 0.9 5 7] >>
stream
q 1.5 0 0 1.25 10 20 cm /Fm1 Do Q
endstream
endobj
8 0 obj
<< /Length 68 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 1 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> /Matrix [1 0 0 1 4 6] >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Nested heading) Tj ET EMC
endstream
endobj
9 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
10 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 8 0 R /MCID 0 >> >>
endobj
11 0 obj
<< /Limits [0 1] /Nums [0 [9 0 R] 1 [10 0 R]] >>
endobj
xref
0 12
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000313 00000 n
0000000393 00000 n
0000000463 00000 n
0000000558 00000 n
0000000858 00000 n
0000001189 00000 n
0000001304 00000 n
0000001420 00000 n
trailer
<< /Size 12 /Root 1 0 R >>
startxref
1485
%%EOF
+52
View File
@@ -0,0 +1,52 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 58 >>
stream
q 1 0 0 1 30 180 cm /Fm0 Do Q q 1 0 0 1 80 60 cm /Fm0 Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Kids [9 0 R] >> >>
endobj
7 0 obj
<< /Length 70 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Repeated heading) Tj ET EMC
endstream
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
9 0 obj
<< /Limits [0 0] /Nums [0 [8 0 R]] >>
endobj
xref
0 10
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000302 00000 n
0000000411 00000 n
0000000481 00000 n
0000000568 00000 n
0000000868 00000 n
0000000983 00000 n
trailer
<< /Size 10 /Root 1 0 R >>
startxref
1036
%%EOF
+46
View File
@@ -0,0 +1,46 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 260] /CropBox [20 30 280 230] /Rotate 90 /StructParents 0 /Resources << /Font << /F1 5 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 137 >>
stream
/H3 <</MCID 1>> BDC BT /F1 16 Tf 60 80 Td (Rotated second) Tj ET EMC
/H1 <</MCID 0>> BDC BT /F1 20 Tf 50 170 Td (Rotated first) Tj ET EMC
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [7 0 R 8 0 R] /ParentTree << /Nums [0 [7 0 R 8 0 R]] >> >>
endobj
7 0 obj
<< /Type /StructElem /S /H1 /P 6 0 R /Pg 3 0 R /K 0 >>
endobj
8 0 obj
<< /Type /StructElem /S /H3 /P 6 0 R /Pg 3 0 R /K 1 >>
endobj
xref
0 9
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000351 00000 n
0000000540 00000 n
0000000610 00000 n
0000000712 00000 n
0000000782 00000 n
trailer
<< /Size 9 /Root 1 0 R >>
startxref
852
%%EOF
Binary file not shown.
Binary file not shown.
+48
View File
@@ -0,0 +1,48 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 7 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 0 /Resources << /XObject << /Fm 6 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 56 >>
stream
/H2 <</MCID 0>> BDC q 1.5 0 0 1.25 55 70 cm /Fm Do Q EMC
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Length 66 /Type /XObject /Subtype /Form /BBox [0 0 160 80] /StructParents 1 /Resources << /Font << /F1 5 0 R >> >> >>
stream
/H2 <</MCID 4>> BDC BT /F1 16 Tf 10 30 Td (Form heading) Tj ET EMC
endstream
endobj
7 0 obj
<< /Type /StructTreeRoot /K [8 0 R] /ParentTree << /Nums [0 [8 0 R] 1 [null null null null 8 0 R]] >> /ParentTreeNextKey 2 >>
endobj
8 0 obj
<< /Type /StructElem /S /H2 /P 7 0 R /Pg 3 0 R /T (Form heading) /K [0 << /Type /MCR /Pg 3 0 R /Stm 6 0 R /MCID 4 >>] >>
endobj
xref
0 9
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000318 00000 n
0000000425 00000 n
0000000495 00000 n
0000000716 00000 n
0000000857 00000 n
trailer
<< /Size 9 /Root 1 0 R >>
startxref
993
%%EOF
+63
View File
@@ -0,0 +1,63 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 6 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 350] /Resources << /XObject << /Fm0 7 0 R /Fm1 8 0 R >> >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 29 >>
stream
q 1 0 0 1 40 100 cm /Fm0 Do Q
endstream
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Type /StructTreeRoot /K [9 0 R 10 0 R] /ParentTree << /Kids [11 0 R] >> >>
endobj
7 0 obj
<< /Length 66 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 0 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Used heading) Tj ET EMC
endstream
endobj
8 0 obj
<< /Length 68 /Type /XObject /Subtype /Form /BBox [0 0 260 90] /StructParents 1 /Resources << /Font << /F1 5 0 R >> /XObject << /Fm0 7 0 R /Fm1 8 0 R >> /Properties << /HeadingProperty << /MCID 0 >> >> >> >>
stream
/H2 <</MCID 0>> BDC BT /F1 12 Tf 10 30 Td (Unused heading) Tj ET EMC
endstream
endobj
9 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 7 0 R /MCID 0 >> >>
endobj
10 0 obj
<< /Type /StructElem /S /H2 /P 6 0 R /Pg 3 0 R /K << /Type /MCR /Pg 3 0 R /Stm 8 0 R /MCID 0 >> >>
endobj
11 0 obj
<< /Limits [0 1] /Nums [0 [9 0 R] 1 [10 0 R]] >>
endobj
xref
0 12
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000313 00000 n
0000000393 00000 n
0000000463 00000 n
0000000558 00000 n
0000000865 00000 n
0000001174 00000 n
0000001289 00000 n
0000001405 00000 n
trailer
<< /Size 12 /Root 1 0 R >>
startxref
1470
%%EOF
+37
View File
@@ -0,0 +1,37 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 5 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 320 260] /StructParents 0 /Resources << >> /Contents 4 0 R >>
endobj
4 0 obj
<< /Length 51 >>
stream
/H4 <</MCID 0>> BDC 0 0 1 rg 40 180 150 20 re f EMC
endstream
endobj
5 0 obj
<< /Type /StructTreeRoot /K [6 0 R] /ParentTree << /Nums [0 [6 0 R]] >> >>
endobj
6 0 obj
<< /Type /StructElem /S /H4 /P 5 0 R /Pg 3 0 R /ActualText (Vector section) /K 0 >>
endobj
xref
0 7
0000000000 65535 f
0000000015 00000 n
0000000115 00000 n
0000000172 00000 n
0000000293 00000 n
0000000395 00000 n
0000000485 00000 n
trailer
<< /Size 7 /Root 1 0 R >>
startxref
584
%%EOF
+117
View File
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
"""Self-authored linear-sRGB ICCBased vector/image fixture; no borrowed ICC data.
Uses public LittleCMS APIs to encode D65 + sRGB primaries + gamma 1. The
color expectation is the analytic sRGB transfer function, independent of PDF
renderer output. Only the ICC creation timestamp is normalized for determinism.
"""
from pathlib import Path
import ctypes as C
import ctypes.util
import hashlib
import json
import shutil
import struct
class xyY(C.Structure):
_fields_ = [("x", C.c_double), ("y", C.c_double), ("Y", C.c_double)]
class Primaries(C.Structure):
_fields_ = [("Red", xyY), ("Green", xyY), ("Blue", xyY)]
def linear_profile():
cms = C.CDLL(ctypes.util.find_library("lcms2") or "liblcms2.so")
cms.cmsGetEncodedCMMversion.restype = C.c_uint32
cms.cmsBuildGamma.argtypes = [C.c_void_p, C.c_double]; cms.cmsBuildGamma.restype = C.c_void_p
cms.cmsFreeToneCurve.argtypes = [C.c_void_p]
cms.cmsCreateRGBProfile.argtypes = [C.POINTER(xyY), C.POINTER(Primaries), C.POINTER(C.c_void_p)]
cms.cmsCreateRGBProfile.restype = C.c_void_p
cms.cmsSaveProfileToMem.argtypes = [C.c_void_p, C.c_void_p, C.POINTER(C.c_uint32)]
cms.cmsSaveProfileToMem.restype = C.c_int
cms.cmsCloseProfile.argtypes = [C.c_void_p]
curve = cms.cmsBuildGamma(None, 1.0)
if not curve: raise RuntimeError("LittleCMS gamma creation failed")
white = xyY(.3127, .3290, 1.)
primaries = Primaries(xyY(.64, .33, 1.), xyY(.30, .60, 1.), xyY(.15, .06, 1.))
curves = (C.c_void_p * 3)(curve, curve, curve)
profile = cms.cmsCreateRGBProfile(C.byref(white), C.byref(primaries), curves)
cms.cmsFreeToneCurve(curve)
if not profile: raise RuntimeError("LittleCMS profile creation failed")
try:
length = C.c_uint32()
if not cms.cmsSaveProfileToMem(profile, None, C.byref(length)): raise RuntimeError("ICC size failed")
buffer = C.create_string_buffer(length.value)
if not cms.cmsSaveProfileToMem(profile, buffer, C.byref(length)): raise RuntimeError("ICC save failed")
data = bytearray(buffer.raw[:length.value])
finally: cms.cmsCloseProfile(profile)
data[24:36] = struct.pack(">6H", 2026, 9, 19, 0, 0, 0)
data[84:100] = bytes(16) # Zero profile ID is permitted; no stale timestamp-derived ID.
assert data[36:40] == b"acsp" and data[16:20] == b"RGB "
return bytes(data), cms.cmsGetEncodedCMMversion()
def srgb(value):
encoded = 12.92 * value if value <= .0031308 else 1.055 * value ** (1 / 2.4) - .055
return round(255 * encoded)
def pdf_stream(data, extra=b""):
return b"<< /Length " + str(len(data)).encode() + b" " + extra + b" >>\nstream\n" + data + b"\nendstream"
def generate(out):
out = Path(out); out.mkdir(parents=True, exist_ok=True)
profile, version = linear_profile()
(out / "linear-srgb.icc").write_bytes(profile)
license_path = Path("/usr/share/licenses/lcms2/LICENSE")
if license_path.is_file(): shutil.copyfile(license_path, out / "LCMS2-LICENSE.txt")
values = [(.0625, .0625, .0625), (.25, .25, .25), (.5, .5, .5), (.75, .75, .75), (.5, .125, .0625), (.0625, .25, .5)]
content = ["0 0 0 rg BT /F1 16 Tf 30 325 Td (EMBEDDED ICC: LINEAR RGB TO sRGB) Tj ET",
"BT /F1 10 Tf 30 298 Td (Top: ICCBased vector / Middle: DeviceRGB control / Bottom: ICCBased image) Tj ET",
"/RelativeColorimetric ri"]
probes = []
for i, value in enumerate(values):
x = 30 + i * 88
operands = " ".join(str(v) for v in value)
content += [f"/Linear cs {operands} scn {x} 216 76 64 re f", f"{operands} rg {x} 132 76 64 re f"]
probes.append({"kind": "icc-vector", "point_pt": [x+38, 248], "components": value, "expected_rgb": [srgb(v) for v in value]})
probes.append({"kind": "device-control", "point_pt": [x+38, 164], "components": value, "expected_rgb": [round(v*255) for v in value]})
quantized = [round(v*255) for v in value]
probes.append({"kind": "icc-image", "point_pt": [30+i*88+44, 68], "components": quantized, "expected_rgb": [srgb(v/255) for v in quantized]})
content += ["q 528 0 0 48 30 44 cm /Sample Do Q", "0 0 0 rg BT /F1 10 Tf 30 22 Td (ICC gamma 1 / D65 / sRGB primaries / original data and coordinates) Tj ET"]
image = bytes(round(v*255) for rgb in values for v in rgb)
objects = [b"<< /Type /Catalog /Pages 2 0 R >>", b"<< /Type /Pages /Count 1 /Kids [3 0 R] >>",
b"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 600 350] /Resources << /Font << /F1 6 0 R >> /ColorSpace << /Linear [/ICCBased 5 0 R] >> /XObject << /Sample 7 0 R >> >> /Contents 4 0 R >>",
pdf_stream("\n".join(content).encode()), pdf_stream(profile,b"/N 3 /Alternate /DeviceRGB /Range [0 1 0 1 0 1]"),
b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
pdf_stream(image,b"/Type /XObject /Subtype /Image /Width 6 /Height 1 /BitsPerComponent 8 /Interpolate false /ColorSpace [/ICCBased 5 0 R] /Intent /RelativeColorimetric")]
data = bytearray(b"%PDF-1.7\n%\xe2\xe3\xcf\xd3\n"); offsets=[0]
for i, obj in enumerate(objects,1):
offsets.append(len(data)); data += f"{i} 0 obj\n".encode()+obj+b"\nendobj\n"
xref=len(data); data += f"xref\n0 {len(offsets)}\n0000000000 65535 f \n".encode()
for offset in offsets[1:]: data += f"{offset:010d} 00000 n \n".encode()
data += f"trailer << /Size {len(offsets)} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n".encode()
name="icc-linear-rgb.pdf"; (out/name).write_bytes(data)
record={"file":name,"sha256":hashlib.sha256(data).hexdigest(),"page_count":1,
"expected":{"page_sizes_pt":[[600,350]],"icc_probes":probes,"probe_tolerance_rgb":3,
"profile_effect":"ICCBased 0.5 linear gray becomes approximately 188, distinct from DeviceRGB approximately 128."},
"limits":["One RGB matrix/TRC profile, not arbitrary ICC LUT/CMYK/printing conformance.","Analytic sRGB color expectation; independent renderer comparison still requires visual review."]}
origin={"file":"linear-srgb.icc","sha256":hashlib.sha256(profile).hexdigest(),"bytes":len(profile),
"source":"Self-created with LittleCMS cmsCreateRGBProfile using the stated numeric white point, primaries and gamma; no third-party ICC profile is copied.",
"lcms_encoded_version":version,"lcms_license":"MIT; LCMS2-LICENSE.txt",
"upstream":"https://github.com/mm2/Little-CMS","profile_copyright_tag":"No copyright, use freely",
"white_xy":[.3127,.3290],"primaries_xy":[[.64,.33],[.30,.60],[.15,.06]],"gamma":1,
"timestamp_normalization":"Header creation time is fixed to 2026-09-19; optional profile ID is zero."}
return record,origin
if __name__ == "__main__":
out=Path(__file__).resolve().parent/"extended"; record,origin=generate(out)
manifest_path=out/"manifest.json"; manifest=json.loads(manifest_path.read_text())
manifest["documents"]=[d for d in manifest["documents"] if d["file"]!=record["file"]]+[record]
manifest["color_profile"]=origin
manifest_path.write_text(json.dumps(manifest,ensure_ascii=False,indent=2)+"\n")
print(json.dumps({"fixture":record["sha256"],"profile":origin["sha256"]}))
+27
View File
@@ -0,0 +1,27 @@
# Soft-mask and pattern rendering-intent probes
This self-authored 4-page PDF contains 108 declared pixel probes. The existing
984-byte distinct CMYK/Lab ICC profile is copied without alteration. Its four
intent outputs for CMYK (0, .75, .25, 0) have separated luminances; no PDF renderer
supplies the expected colors.
[Adobe PDF Reference 1.4](https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.4.pdf)
pp. 218, 223, 231 and 453 define pattern state. Colored tiling and shading patterns
start with their resource-owning page/Form stream's initial state. A Form is
reused under different initial intents, then changes its painting intent to
Absolute. Explicit pattern overrides and q/Q are separate controls. Uncolored
stencils contain no color operators or `ri`; their ICC base color is supplied by
the caller. Small/large uncolored strokes distinguish stroke from fill color.
Pages 440–446 define luminosity soft masks and their backdrop. The mask's RGB
group contains one opaque ICC rectangle, or no objects for the BC-only controls.
The direct CMM RGB result is reduced with the recommended .30/.59/.11 weights;
black over white has value 255 minus that luminosity. This device-dependent
formula is a declared test convention, not universal device calibration.
Run `tests/cmyk_lut/transparency.py --self-check --output NEW_DIRECTORY`, or pass
`--build-dir build --pdfium-library PATH/libpdfium.so --output NEW_DIRECTORY`.
The runner records all failures, validates the sandbox helper and library hash,
and judges PDFium and Poppler separately against the direct CMM. LittleCMS may
be shared with the renderers; this is not an independent CMM implementation or
general ICC conformance acceptance. The older 8-page intent fixture is unchanged.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [4 0 R] >>
endobj
4 0 obj
<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /AP << /N 42 >> >>
endobj
xref
0 5
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000121 00000 n
0000000225 00000 n
trailer
<< /Size 5 /Root 1 0 R >>
startxref
310
%%EOF
+26
View File
@@ -0,0 +1,26 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [4 0 R] >>
endobj
4 0 obj
<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /C [0 1] >>
endobj
xref
0 5
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000121 00000 n
0000000225 00000 n
trailer
<< /Size 5 /Root 1 0 R >>
startxref
303
%%EOF
+26
View File
@@ -0,0 +1,26 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [4 0 R] >>
endobj
4 0 obj
<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /BS << /S /D /D [0 0] >> >>
endobj
xref
0 5
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000121 00000 n
0000000225 00000 n
trailer
<< /Size 5 /Root 1 0 R >>
startxref
319
%%EOF
+266
View File
@@ -0,0 +1,266 @@
{
"generator": "generate_link_borders.py",
"license": "Self-created test content; same license as DocView.",
"fixtures": [
{
"file": "styles.pdf",
"bytes": 5335,
"sha256": "add7f02f5295f39b9bd340151f7c7ea0b50786c89f66af791215df2c13badf1b",
"pages": 4,
"annotations": [
{
"name": "default",
"rect": [
40,
50,
140,
80
],
"has_border": true
},
{
"name": "solid-rgb",
"rect": [
160,
50,
260,
80
],
"has_border": true
},
{
"name": "dashed-border",
"rect": [
280,
50,
380,
80
],
"has_border": true
},
{
"name": "dashed-bs-odd",
"rect": [
400,
50,
500,
80
],
"has_border": true
},
{
"name": "dashed-default",
"rect": [
40,
125,
140,
155
],
"has_border": true
},
{
"name": "underline",
"rect": [
160,
125,
260,
155
],
"has_border": true
},
{
"name": "bs-overrides-border",
"rect": [
280,
125,
380,
155
],
"has_border": true
},
{
"name": "zero-width",
"rect": [
400,
125,
500,
155
],
"has_border": false
},
{
"name": "transparent",
"rect": [
40,
200,
140,
230
],
"has_border": false
},
{
"name": "hidden",
"rect": [
160,
200,
260,
230
],
"has_border": false
},
{
"name": "no-view",
"rect": [
280,
200,
380,
230
],
"has_border": false
},
{
"name": "print-flag-visible",
"rect": [
400,
200,
500,
230
],
"has_border": true
},
{
"name": "gray",
"rect": [
40,
275,
140,
305
],
"has_border": true
},
{
"name": "cmyk",
"rect": [
160,
275,
260,
305
],
"has_border": true
},
{
"name": "rounded",
"rect": [
280,
275,
380,
305
],
"has_border": true
},
{
"name": "beveled",
"rect": [
400,
275,
500,
305
],
"has_border": true
},
{
"name": "inset",
"rect": [
40,
350,
140,
380
],
"has_border": true
},
{
"name": "appearance-preserved",
"rect": [
160,
350,
260,
380
],
"has_border": true
},
{
"name": "empty-appearance-preserved",
"rect": [
280,
350,
380,
380
],
"has_border": false
},
{
"name": "alpha",
"rect": [
400,
350,
500,
380
],
"has_border": true
}
],
"reference_limitations": [
"Poppler ignores gray/CMYK border colors, rounded corners, bevel/inset, and alpha in its no-AP link fallback; assert these independently.",
"Saved normal AP must be preserved without adding a second border, even if Poppler adds one."
]
},
{
"file": "unknown-style.pdf",
"bytes": 479,
"sha256": "d4143011ea2114f4fbb0d39c10b4dac9d4a66a58cc6af6f70ee8d3feb6dc4fc5",
"render_error": "E_PDF_ANNOT_UNSUPPORTED"
},
{
"file": "no-zoom.pdf",
"bytes": 462,
"sha256": "e84b3c14db58235d6d4020abb99e3ed76cb2b95b49a4a134a3e41957270b8bfe",
"expected": "Valid annotation flag; rendering succeeds. Geometry coverage is in annotation-flags/flags.pdf."
},
{
"file": "no-rotate.pdf",
"bytes": 463,
"sha256": "ffacbbb08144ad880b6d582fa90199fabea4935601ceed5f9acc17a8d4231656",
"expected": "Valid annotation flag; rendering succeeds. Geometry coverage is in annotation-flags/flags.pdf."
},
{
"file": "invalid-dash.pdf",
"bytes": 482,
"sha256": "41ad1db315a360b98bb84c2fb44e5cb65eff5a690d9246fb3cd18b1f262858d7",
"render_error": "E_PDF_CORRUPT"
},
{
"file": "oversized-dash.pdf",
"bytes": 609,
"sha256": "51ecdef6659ea919b38985d21e4cc65f352f22654ecf47efd1670eea1b931640",
"render_error": "E_LIMIT_EXCEEDED"
},
{
"file": "invalid-color.pdf",
"bytes": 466,
"sha256": "eeb32339cc56e21cb6c3f2964c035746e0e233cfb694eb9bb9dafd1850010465",
"render_error": "E_PDF_CORRUPT"
},
{
"file": "invalid-ap.pdf",
"bytes": 473,
"sha256": "d604660b85493a4fe7f68062597b0e0f08f4a9d26029ad1b11afa661c629502b",
"render_error": "E_PDF_CORRUPT"
},
{
"file": "retry-budget.pdf",
"bytes": 127908,
"sha256": "bb1145397f88a941e1597ed485fcab7a141bd6b11a82403a96bd646ec8d28e79",
"expected": "Forty failed page-0 decodes must not charge discarded appearances or prevent valid page-1 rendering."
}
]
}
+26
View File
@@ -0,0 +1,26 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [4 0 R] >>
endobj
4 0 obj
<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /F 16 >>
endobj
xref
0 5
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000121 00000 n
0000000225 00000 n
trailer
<< /Size 5 /Root 1 0 R >>
startxref
300
%%EOF
+26
View File
@@ -0,0 +1,26 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [4 0 R] >>
endobj
4 0 obj
<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /F 8 >>
endobj
xref
0 5
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000121 00000 n
0000000225 00000 n
trailer
<< /Size 5 /Root 1 0 R >>
startxref
299
%%EOF
+26
View File
@@ -0,0 +1,26 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [4 0 R] >>
endobj
4 0 obj
<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /BS << /S /D /D [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ] >> >>
endobj
xref
0 5
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000121 00000 n
0000000225 00000 n
trailer
<< /Size 5 /Root 1 0 R >>
startxref
446
%%EOF
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 4 /Kids [3 0 R 4 0 R 5 0 R 6 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 550 470] /CropBox [20 30 530 450] /Rotate 0 /Resources << >> /Annots [9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R] >>
endobj
4 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 550 470] /CropBox [20 30 530 450] /Rotate 90 /Resources << >> /Annots [9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R] >>
endobj
5 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 550 470] /CropBox [20 30 530 450] /Rotate 180 /Resources << >> /Annots [9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R] >>
endobj
6 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 550 470] /CropBox [20 30 530 450] /Rotate 270 /Resources << >> /Annots [9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R] >>
endobj
7 0 obj
<< /Length 26 /Type /XObject /Subtype /Form /BBox [0 0 100 30] /Resources << >> >>
stream
0 0.8 0 rg 0 0 100 30 re f
endstream
endobj
8 0 obj
<< /Length 0 /Type /XObject /Subtype /Form /BBox [0 0 100 30] /Resources << >> >>
stream
endstream
endobj
9 0 obj
<< /Type /Annot /Subtype /Link /Rect [40 50 140 80] /A << /S /URI /URI (https://example.org/default) >> >>
endobj
10 0 obj
<< /Type /Annot /Subtype /Link /Rect [160 50 260 80] /A << /S /URI /URI (https://example.org/solid-rgb) >> /BS << /W 3 /S /S >> /C [0.8 0.1 0.2] >>
endobj
11 0 obj
<< /Type /Annot /Subtype /Link /Rect [280 50 380 80] /A << /S /URI /URI (https://example.org/dashed-border) >> /Border [0 0 2 [6 3]] /C [0 0.2 0.8] >>
endobj
12 0 obj
<< /Type /Annot /Subtype /Link /Rect [400 50 500 80] /A << /S /URI /URI (https://example.org/dashed-bs-odd) >> /BS << /W 2 /S /D /D [7 3 2] >> /C [0.1 0.5 0.2] >>
endobj
13 0 obj
<< /Type /Annot /Subtype /Link /Rect [40 125 140 155] /A << /S /URI /URI (https://example.org/dashed-default) >> /BS << /W 2 /S /D >> >>
endobj
14 0 obj
<< /Type /Annot /Subtype /Link /Rect [160 125 260 155] /A << /S /URI /URI (https://example.org/underline) >> /BS << /W 3 /S /U >> /C [0.6 0.1 0.8] >>
endobj
15 0 obj
<< /Type /Annot /Subtype /Link /Rect [280 125 380 155] /A << /S /URI /URI (https://example.org/bs-overrides-border) >> /Border [9 9 12 [1 1]] /BS << /W 2 /S /S >> /C [0 0.3 0.7] >>
endobj
16 0 obj
<< /Type /Annot /Subtype /Link /Rect [400 125 500 155] /A << /S /URI /URI (https://example.org/zero-width) >> /BS << /W 0 >> >>
endobj
17 0 obj
<< /Type /Annot /Subtype /Link /Rect [40 200 140 230] /A << /S /URI /URI (https://example.org/transparent) >> /BS << /W 4 >> /C [] >>
endobj
18 0 obj
<< /Type /Annot /Subtype /Link /Rect [160 200 260 230] /A << /S /URI /URI (https://example.org/hidden) >> /BS << /W 4 >> /F 2 >>
endobj
19 0 obj
<< /Type /Annot /Subtype /Link /Rect [280 200 380 230] /A << /S /URI /URI (https://example.org/no-view) >> /BS << /W 4 >> /F 32 >>
endobj
20 0 obj
<< /Type /Annot /Subtype /Link /Rect [400 200 500 230] /A << /S /URI /URI (https://example.org/print-flag-visible) >> /BS << /W 2 >> /F 4 >>
endobj
21 0 obj
<< /Type /Annot /Subtype /Link /Rect [40 275 140 305] /A << /S /URI /URI (https://example.org/gray) >> /BS << /W 3 >> /C [0.5] >>
endobj
22 0 obj
<< /Type /Annot /Subtype /Link /Rect [160 275 260 305] /A << /S /URI /URI (https://example.org/cmyk) >> /BS << /W 3 >> /C [1 0 0 0] >>
endobj
23 0 obj
<< /Type /Annot /Subtype /Link /Rect [280 275 380 305] /A << /S /URI /URI (https://example.org/rounded) >> /Border [8 6 2] /C [0.6 0.3 0.1] >>
endobj
24 0 obj
<< /Type /Annot /Subtype /Link /Rect [400 275 500 305] /A << /S /URI /URI (https://example.org/beveled) >> /BS << /W 3 /S /B >> /C [0.2 0.6 0.8] >>
endobj
25 0 obj
<< /Type /Annot /Subtype /Link /Rect [40 350 140 380] /A << /S /URI /URI (https://example.org/inset) >> /BS << /W 3 /S /I >> /C [0.2 0.6 0.8] >>
endobj
26 0 obj
<< /Type /Annot /Subtype /Link /Rect [160 350 260 380] /A << /S /URI /URI (https://example.org/appearance-preserved) >> /BS << /W 8 /S /D >> /C [1 0 0] /AP << /N 7 0 R >> >>
endobj
27 0 obj
<< /Type /Annot /Subtype /Link /Rect [280 350 380 380] /A << /S /URI /URI (https://example.org/empty-appearance-preserved) >> /BS << /W 8 >> /AP << /N 8 0 R >> >>
endobj
28 0 obj
<< /Type /Annot /Subtype /Link /Rect [400 350 500 380] /A << /S /URI /URI (https://example.org/alpha) >> /BS << /W 3 >> /C [0 0 1] /CA 0.5 >>
endobj
xref
0 29
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000139 00000 n
0000000411 00000 n
0000000684 00000 n
0000000958 00000 n
0000001232 00000 n
0000001374 00000 n
0000001489 00000 n
0000001612 00000 n
0000001776 00000 n
0000001943 00000 n
0000002122 00000 n
0000002275 00000 n
0000002441 00000 n
0000002638 00000 n
0000002782 00000 n
0000002932 00000 n
0000003077 00000 n
0000003224 00000 n
0000003381 00000 n
0000003527 00000 n
0000003678 00000 n
0000003837 00000 n
0000004001 00000 n
0000004162 00000 n
0000004352 00000 n
0000004531 00000 n
trailer
<< /Size 29 /Root 1 0 R >>
startxref
4689
%%EOF
+26
View File
@@ -0,0 +1,26 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Count 1 /Kids [3 0 R] >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << >> /Annots [4 0 R] >>
endobj
4 0 obj
<< /Type /Annot /Subtype /Link /Rect [20 20 80 80] /BS << /S /Unknown >> >>
endobj
xref
0 5
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000121 00000 n
0000000225 00000 n
trailer
<< /Size 5 /Root 1 0 R >>
startxref
316
%%EOF
+98
View File
@@ -0,0 +1,98 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /Outlines 8 0 R /PageLabels << /Nums [0 << /S /r >> 1 << /S /D /St 1 >>] >> /StructTreeRoot 11 0 R /MarkInfo << /Marked true >> /AcroForm << /Fields [16 0 R] /DR << /Font << /F1 7 0 R >> >> /DA (/F1 12 Tf 0 g) >> /Names << /Dests << /Names [(second) [4 0 R /XYZ 40 200 null]] >> >> >>
endobj
2 0 obj
<< /Type /Pages /Kids [3 0 R 4 0 R] /Count 2 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 240 260] /CropBox [20 30 220 230] /Resources << /Font << /F1 7 0 R >> >> /Contents 5 0 R /StructParents 0 /Annots [14 0 R 15 0 R 16 0 R 18 0 R] >>
endobj
4 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Rotate 90 /Resources << /Font << /F1 7 0 R >> >> /Contents 6 0 R >>
endobj
5 0 obj
<< /Length 221 >>
stream
0 g 40 50 40 40 re f
/Chapter <</MCID 0>> BDC BT /F1 16 Tf 60 180 Td (Heading One) Tj ET EMC
/H2 <</MCID 1>> BDC BT /F1 12 Tf 60 120 Td (Needle) Tj ET EMC
/H2 <</MCID 2>> BDC BT /F1 12 Tf 60 100 Td (Second MCID) Tj ET EMC
endstream
endobj
6 0 obj
<< /Length 49 >>
stream
BT /F1 20 Tf 40 100 Td (Second Page Needle) Tj ET
endstream
endobj
7 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
8 0 obj
<< /Type /Outlines /First 9 0 R /Last 10 0 R /Count 2 >>
endobj
9 0 obj
<< /Title (First heading) /Parent 8 0 R /Dest [3 0 R /XYZ 60 180 null] /Next 10 0 R >>
endobj
10 0 obj
<< /Title (Named second) /Parent 8 0 R /Dest (second) /Prev 9 0 R >>
endobj
11 0 obj
<< /Type /StructTreeRoot /K [12 0 R 13 0 R] /RoleMap << /Chapter /H1 >> /ParentTree << /Nums [0 [12 0 R 13 0 R 13 0 R]] >> >>
endobj
12 0 obj
<< /Type /StructElem /S /Chapter /P 11 0 R /Pg 3 0 R /K 0 >>
endobj
13 0 obj
<< /Type /StructElem /S /H2 /P 11 0 R /Pg 3 0 R /K [1 2] >>
endobj
14 0 obj
<< /Type /Annot /Subtype /Link /Rect [30 30 90 45] /A << /S /URI /URI (https://example.org/) >> >>
endobj
15 0 obj
<< /Type /Annot /Subtype /Link /Rect [100 30 160 45] /A << /S /Launch /F (/tmp/never-execute) >> >>
endobj
16 0 obj
<< /Type /Annot /Subtype /Widget /FT /Tx /T (ReadonlyField) /V (Saved) /Ff 1 /F 4 /Rect [120 60 160 90] /P 3 0 R >>
endobj
17 0 obj
<< /Length 23 /Type /XObject /Subtype /Form /BBox [0 0 40 30] /Resources << >> >>
stream
1 0 0 rg 0 0 40 30 re f
endstream
endobj
18 0 obj
<< /Type /Annot /Subtype /Text /Rect [180 200 200 220] /Contents (Read-only comment) /F 4 >>
endobj
19 0 obj
<< /Title (DocView PDF fixture) /Author (DocView tests) >>
endobj
xref
0 20
0000000000 65535 f
0000000015 00000 n
0000000346 00000 n
0000000409 00000 n
0000000615 00000 n
0000000752 00000 n
0000001025 00000 n
0000001125 00000 n
0000001195 00000 n
0000001267 00000 n
0000001369 00000 n
0000001454 00000 n
0000001596 00000 n
0000001673 00000 n
0000001749 00000 n
0000001864 00000 n
0000001980 00000 n
0000002112 00000 n
0000002251 00000 n
0000002360 00000 n
trailer
<< /Size 20 /Root 1 0 R /Info 19 0 R >>
startxref
2435
%%EOF
+98
View File
@@ -0,0 +1,98 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /Outlines 8 0 R /PageLabels << /Nums [0 << /S /r >> 1 << /S /D /St 1 >>] >> /StructTreeRoot 11 0 R /MarkInfo << /Marked true >> /AcroForm << /Fields [16 0 R] /DR << /Font << /F1 7 0 R >> >> /DA (/F1 12 Tf 0 g) >> /Names << /Dests << /Names [(second) [4 0 R /XYZ 40 200 null]] >> >> >>
endobj
2 0 obj
<< /Type /Pages /Kids [null 4 0 R] /Count 2 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 240 260] /CropBox [20 30 220 230] /Resources << /Font << /F1 7 0 R >> >> /Contents 5 0 R /StructParents 0 /Annots [14 0 R 15 0 R 16 0 R 18 0 R] >>
endobj
4 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Rotate 90 /Resources << /Font << /F1 7 0 R >> >> /Contents 6 0 R >>
endobj
5 0 obj
<< /Length 221 >>
stream
0 g 40 50 40 40 re f
/Chapter <</MCID 0>> BDC BT /F1 16 Tf 60 180 Td (Heading One) Tj ET EMC
/H2 <</MCID 1>> BDC BT /F1 12 Tf 60 120 Td (Needle) Tj ET EMC
/H2 <</MCID 2>> BDC BT /F1 12 Tf 60 100 Td (Second MCID) Tj ET EMC
endstream
endobj
6 0 obj
<< /Length 49 >>
stream
BT /F1 20 Tf 40 100 Td (Second Page Needle) Tj ET
endstream
endobj
7 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
8 0 obj
<< /Type /Outlines /First 9 0 R /Last 10 0 R /Count 2 >>
endobj
9 0 obj
<< /Title (First heading) /Parent 8 0 R /Dest [3 0 R /XYZ 60 180 null] /Next 10 0 R >>
endobj
10 0 obj
<< /Title (Named second) /Parent 8 0 R /Dest (second) /Prev 9 0 R >>
endobj
11 0 obj
<< /Type /StructTreeRoot /K [12 0 R 13 0 R] /RoleMap << /Chapter /H1 >> /ParentTree << /Nums [0 [12 0 R 13 0 R 13 0 R]] >> >>
endobj
12 0 obj
<< /Type /StructElem /S /Chapter /P 11 0 R /Pg 3 0 R /K 0 >>
endobj
13 0 obj
<< /Type /StructElem /S /H2 /P 11 0 R /Pg 3 0 R /K [1 2] >>
endobj
14 0 obj
<< /Type /Annot /Subtype /Link /Rect [30 30 90 45] /A << /S /URI /URI (https://example.org/) >> >>
endobj
15 0 obj
<< /Type /Annot /Subtype /Link /Rect [100 30 160 45] /A << /S /Launch /F (/tmp/never-execute) >> >>
endobj
16 0 obj
<< /Type /Annot /Subtype /Widget /FT /Tx /T (ReadonlyField) /V (Saved) /Ff 1 /F 4 /Rect [120 60 160 90] /P 3 0 R /AP << /N 17 0 R >> >>
endobj
17 0 obj
<< /Length 23 /Type /XObject /Subtype /Form /BBox [0 0 40 30] /Resources << >> >>
stream
1 0 0 rg 0 0 40 30 re f
endstream
endobj
18 0 obj
<< /Type /Annot /Subtype /Text /Rect [180 200 200 220] /Contents (Read-only comment) /F 4 >>
endobj
19 0 obj
<< /Title (DocView PDF fixture) /Author (DocView tests) >>
endobj
xref
0 20
0000000000 65535 f
0000000015 00000 n
0000000346 00000 n
0000000408 00000 n
0000000614 00000 n
0000000751 00000 n
0000001024 00000 n
0000001124 00000 n
0000001194 00000 n
0000001266 00000 n
0000001368 00000 n
0000001453 00000 n
0000001595 00000 n
0000001672 00000 n
0000001748 00000 n
0000001863 00000 n
0000001979 00000 n
0000002131 00000 n
0000002270 00000 n
0000002379 00000 n
trailer
<< /Size 20 /Root 1 0 R /Info 19 0 R >>
startxref
2454
%%EOF
+98
View File
@@ -0,0 +1,98 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /Outlines 8 0 R /PageLabels << /Nums [0 << /S /r >> 1 << /S /D /St 1 >>] >> /StructTreeRoot 11 0 R /MarkInfo << /Marked true >> /AcroForm << /Fields [16 0 R] /DR << /Font << /F1 7 0 R >> >> /DA (/F1 12 Tf 0 g) >> /Names << /Dests << /Names [(second) [4 0 R /XYZ 40 200 null]] >> >> >>
endobj
2 0 obj
<< /Type /Pages /Kids [3 0 R 4 0 R] /Count 2 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 240 260] /CropBox [20 30 220 230] /Resources << /Font << /F1 7 0 R >> >> /Contents 5 0 R /StructParents 0 /Annots [14 0 R 15 0 R 16 0 R 18 0 R] >>
endobj
4 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Rotate 90 /Resources << /Font << /F1 7 0 R >> >> /Contents 6 0 R >>
endobj
5 0 obj
<< /Length 221 >>
stream
0 g 40 50 40 40 re f
/Chapter <</MCID 0>> BDC BT /F1 16 Tf 60 180 Td (Heading One) Tj ET EMC
/H2 <</MCID 1>> BDC BT /F1 12 Tf 60 120 Td (Needle) Tj ET EMC
/H2 <</MCID 2>> BDC BT /F1 12 Tf 60 100 Td (Second MCID) Tj ET EMC
endstream
endobj
6 0 obj
<< /Length 49 >>
stream
BT /F1 20 Tf 40 100 Td (Second Page Needle) Tj ET
endstream
endobj
7 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
8 0 obj
<< /Type /Outlines /First 9 0 R /Last 10 0 R /Count 2 >>
endobj
9 0 obj
<< /Title (First heading) /Parent 8 0 R /Dest [3 0 R /XYZ 60 180 null] /Next 10 0 R >>
endobj
10 0 obj
<< /Title (Named second) /Parent 8 0 R /Dest (second) /Prev 9 0 R >>
endobj
11 0 obj
<< /Type /StructTreeRoot /K [12 0 R 13 0 R] /RoleMap << /Chapter /H1 >> /ParentTree << /Nums [0 [12 0 R 13 0 R 13 0 R]] >> >>
endobj
12 0 obj
<< /Type /StructElem /S /Chapter /P 11 0 R /Pg 3 0 R /K 0 >>
endobj
13 0 obj
<< /Type /StructElem /S /H2 /P 11 0 R /Pg 3 0 R /K [1 2] >>
endobj
14 0 obj
<< /Type /Annot /Subtype /Link /Rect [30 30 90 45] /A << /S /URI /URI (https://example.org/) >> >>
endobj
15 0 obj
<< /Type /Annot /Subtype /Link /Rect [100 30 160 45] /A << /S /Launch /F (/tmp/never-execute) >> >>
endobj
16 0 obj
<< /Type /Annot /Subtype /Widget /FT /Tx /T (ReadonlyField) /V (Saved) /Ff 1 /F 4 /Rect [120 60 160 90] /P 3 0 R /AP << /N 17 0 R >> >>
endobj
17 0 obj
<< /Length 23 /Type /XObject /Subtype /Form /BBox [0 0 40 30] /Resources << >> >>
stream
1 0 0 rg 0 0 40 30 re f
endstream
endobj
18 0 obj
<< /Type /Annot /Subtype /Text /Rect [180 200 200 220] /Contents (Read-only comment) /F 4 >>
endobj
19 0 obj
<< /Title (DocView PDF fixture) /Author (DocView tests) >>
endobj
xref
0 20
0000000000 65535 f
0000000015 00000 n
0000000346 00000 n
0000000409 00000 n
0000000615 00000 n
0000000752 00000 n
0000001025 00000 n
0000001125 00000 n
0000001195 00000 n
0000001267 00000 n
0000001369 00000 n
0000001454 00000 n
0000001596 00000 n
0000001673 00000 n
0000001749 00000 n
0000001864 00000 n
0000001980 00000 n
0000002132 00000 n
0000002271 00000 n
0000002380 00000 n
trailer
<< /Size 20 /Root 1 0 R /Info 19 0 R >>
startxref
2455
%%EOF
+95
View File
@@ -0,0 +1,95 @@
%PDF-1.7
%¿÷¢þ
1 0 obj
<< /AcroForm << /DA <e3038fef51a026530b2cbb71c069ee25bcceab60b5f1dcaad9d8610f711ecdef> /DR << /Font << /F1 3 0 R >> >> /Fields [ 4 0 R ] >> /Extensions << /ADBE << /BaseVersion /1.7 /ExtensionLevel 8 >> >> /MarkInfo << /Marked true >> /Names << /Dests << /Names [ <930121e75f2163b68fb966a28e4e23853de74b172d075c2ba92f8957b69b88ea> [ 5 0 R /XYZ 40 200 null ] ] >> >> /Outlines 6 0 R /PageLabels << /Nums [ 0 << /S /r >> 1 << /S /D /St 1 >> ] >> /Pages 7 0 R /StructTreeRoot 8 0 R /Type /Catalog >>
endobj
2 0 obj
<< /Author <9d1c24f3c84b91bf7ab0ba115388fedb979be3495ef656e009e97e6cbd971899> /Title <d1ba2ab5ca67896bb42f4e372eba10e0a757f1e9158e3858140296ad62a9058675c3bd4d16311e0450b1279eb4bbfd66> >>
endobj
3 0 obj
<< /BaseFont /Helvetica /Subtype /Type1 /Type /Font >>
endobj
4 0 obj
<< /AP << /N 9 0 R >> /F 4 /FT /Tx /Ff 1 /P 10 0 R /Rect [ 120 60 160 90 ] /Subtype /Widget /T <205888fb48abfc80cc7a5410c6fe8a3ff5dc5b6a25ba0202fa773344d97815cc> /Type /Annot /V <6f0852a4359795436be36fa05f909acf00aee603f75e4a8582573c23ca176aef> >>
endobj
5 0 obj
<< /Contents 11 0 R /MediaBox [ 0 0 300 200 ] /Parent 7 0 R /Resources << /Font << /F1 3 0 R >> >> /Rotate 90 /Type /Page >>
endobj
6 0 obj
<< /Count 2 /First 12 0 R /Last 13 0 R /Type /Outlines >>
endobj
7 0 obj
<< /Count 2 /Kids [ 10 0 R 5 0 R ] /Type /Pages >>
endobj
8 0 obj
<< /K [ 14 0 R 15 0 R ] /ParentTree << /Nums [ 0 [ 14 0 R 15 0 R 15 0 R ] ] >> /RoleMap << /Chapter /H1 >> /Type /StructTreeRoot >>
endobj
9 0 obj
<< /BBox [ 0 0 40 30 ] /Resources << >> /Subtype /Form /Type /XObject /Length 48 /Filter /FlateDecode >>
stream
÷J>áY±[lõn|lt%®ëwaÁ¼ò44úv–­ÏeîúJ4Ão¨®Ñ×èhendstream
endobj
10 0 obj
<< /Annots [ 16 0 R 17 0 R 4 0 R 18 0 R ] /Contents 19 0 R /CropBox [ 20 30 220 230 ] /MediaBox [ 0 0 240 260 ] /Parent 7 0 R /Resources << /Font << /F1 3 0 R >> >> /StructParents 0 /Type /Page >>
endobj
11 0 obj
<< /Length 80 /Filter /FlateDecode >>
stream
i::õª(S×4 hF€ˆ,»ÜƒWáÝq3MÛèT5²Ç”€½ä4ªO␍¸KO‰uýíñ·-&|Þöï“;ÛÜ"¸‡À³w‰„Ú§Ûendstream
endobj
12 0 obj
<< /Dest [ 10 0 R /XYZ 60 180 null ] /Next 13 0 R /Parent 6 0 R /Title <3f0660f7e0364deb7a6d9d4f650779613b1b712ce997eae36743e725bfd6b2f0> >>
endobj
13 0 obj
<< /Dest <6c54eec3fdd7b6454631cb7edff8544dd8f9be77710609b3ebbf5f983d080076> /Parent 6 0 R /Prev 12 0 R /Title <00352414b78762c4d009b9918892f3eb6e451db750952440cd80869d86e4c040> >>
endobj
14 0 obj
<< /K 0 /P 8 0 R /Pg 10 0 R /S /Chapter /Type /StructElem >>
endobj
15 0 obj
<< /K [ 1 2 ] /P 8 0 R /Pg 10 0 R /S /H2 /Type /StructElem >>
endobj
16 0 obj
<< /A << /S /URI /URI <9f31a2fc839e3d166438d29c32f24ac7c0ff228493dcdd043cdbdf0d042b9852c2855a841aa8d31b908ffdace9a3f3ff> >> /Rect [ 30 30 90 45 ] /Subtype /Link /Type /Annot >>
endobj
17 0 obj
<< /A << /F <ca5bafe354ce6d887113026ae190a0599df21f442eeda96944f1d36c6cf7fddb602bec7c03fc727fcafdb807da8b1575> /S /Launch >> /Rect [ 100 30 160 45 ] /Subtype /Link /Type /Annot >>
endobj
18 0 obj
<< /Contents <a5a345a0a33646b045fbc1938662569e0b6298068c4731e5ce1d35876ff2972229ab805657c0e09c445978200a5b9dd9> /F 4 /Rect [ 180 200 200 220 ] /Subtype /Text /Type /Annot >>
endobj
19 0 obj
<< /Length 160 /Filter /FlateDecode >>
stream
GyèTzî9Þ ÐÅû~¦y�ß¹�m('–Èí–½Ê;/Ú)[Y‰³­�4õv¿˜ò\.% dÉPQ“,—v�Ì`B!sˆãQb‰†‰.óêÖLÛöWÚÃC+bϳ¿ âÝ×�^“K¹ñ†jÐýs‹M1Õ]X7¢ fdÜfv4ìJ?ñ¹€5ó-Ã7½ì»ÜÍi_h*ΊÊÑG¾P“¼0W>oendstream
endobj
20 0 obj
<< /CF << /StdCF << /AuthEvent /DocOpen /CFM /AESV3 /Length 32 >> >> /Filter /Standard /Length 256 /O <8e3a3c770c7192af39f46d574244ff959c9d96bed97e2e6efca10f68c284d0753228ca01dd122e5d93bb7fd442d9be9e> /OE <86589a9df8290fe4ba0630daffd444f5d19acb902d1a56dec5074491b1cf328d> /P -4 /Perms <d637027e2f15fccc0c3466998b66e8bd> /R 6 /StmF /StdCF /StrF /StdCF /U <298201e5d0e71639e3bbc2a820c9db1c086c46ad5d6d38854af86f29a1e0a156289531fa6128de0c678f7d1c3e84be13> /UE <c93ea802a4991aee8ec02ea2cef1d35aa7f9f15e5ee59d913e903fdfa9154fde> /V 5 >>
endobj
xref
0 21
0000000000 65535 f
0000000015 00000 n
0000000527 00000 n
0000000729 00000 n
0000000799 00000 n
0000001062 00000 n
0000001202 00000 n
0000001275 00000 n
0000001341 00000 n
0000001488 00000 n
0000001673 00000 n
0000001886 00000 n
0000002037 00000 n
0000002194 00000 n
0000002390 00000 n
0000002467 00000 n
0000002545 00000 n
0000002738 00000 n
0000002934 00000 n
0000003124 00000 n
0000003356 00000 n
trailer << /Info 2 0 R /Root 1 0 R /Size 21 /ID [<b2b9e9486b1d5627f1231bef6e9a8883><b2b9e9486b1d5627f1231bef6e9a8883>] /Encrypt 20 0 R >>
startxref
3904
%%EOF
+24
View File
@@ -0,0 +1,24 @@
# Rendering intent expectations, revision 2
The PDF and both ICC profiles are byte-identical to `../rendering-intents`.
Only the eight `shading-pattern-inherit` expected-intent rows are corrected:
an absent pattern ExtGState RI inherits the graphics state at the defining
content stream's entry. These are page streams, with initial RelativeColorimetric.
The later paint-time `ri` does not replace that initial value.
The original manifest is retained as historical failed-oracle evidence. Revision 2
records its hash and the correction tool hash. No rendered pixel was used to
select the corrected intent. Explicit pattern RI overrides are unchanged.
Reference: Adobe PDF Reference 1.4, section 4.6.3, Table 4.23, printed page 231.
Regenerate into a new directory:
```sh
python3 tests/cmyk_lut/correct_intent_oracle.py --output NEW_DIRECTORY
```
Validate with `tests/cmyk_lut/intents.py --corpus
tests/fixtures/pdf/rendering-intents-context`. The separate four-page
`intent-transparency` fixture covers initial page/Form state, repeated pattern
use, explicit overrides, uncolored fill/stroke and luminosity masks.
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
# ICC rendering-intent regression corpus
`rendering-intents.pdf` contains 8 pages and 200 interior-color probes. It is self-authored PDF 1.7 test material, with no borrowed press characterization or renderer-generated golden. Its SHA-256 is `ce59287f6cb2c256c87fcea00a183fa655a165e5028056f28c8c78ddea6645b8`. Exact probe coordinates, intended graphics states, content operators and source hashes are in [manifest.json](manifest.json).
Two ICC v2 CMYK→Lab input profiles exercise the same PDF operations:
- `original-cmyk-lab.icc` is byte-identical to the existing `../cmyk-lut/synthetic-cmyk-lab.icc` (SHA-256 `1708392182ecb3819bb0e4bd1139677be24c9884fff84ad3bb91af5dd42b78f7`). Its A2B0 table alone cannot distinguish Relative, Saturation and Absolute.
- `distinct-cmyk-lab.icc` extends that self-authored binary layout with separate A2B0/A2B1/A2B2 linear CLUTs and media white point `(0.82, 0.86, 0.72)` (SHA-256 `b9a40bfc18e8280eefe0fedc4e607467e1cc27adeee3beb77f4a2b83fc7e9315`). The A2B1/A2B2 black endpoint is Lab `(0,0,0)` to isolate intent selection from a CMM's optional black-point compensation. The original profile is unchanged.
For CMYK bytes `(51,128,204,77)`, direct LittleCMS 2.19 and Pillow/LittleCMS produce these RGB values:
| Intent | Original profile | Distinct profile |
|---|---|---|
| Perceptual | 187,165,145 | 187,165,145 |
| RelativeColorimetric | 193,171,151 | 166,132,101 |
| Saturation | 193,171,151 | 127,143,114 |
| AbsoluteColorimetric | 193,171,151 | 153,124,95 |
The smallest pairwise maximum-channel difference in the distinct profile is 13, greater than twice the fixed 4-level raster tolerance. The runner independently verifies all 64 CLUT vertices from coefficient equations, then computes reference colors directly from the ICC bytes and expected intent using public LittleCMS APIs with floating-point CMYK input. Pillow's 8-bit path cross-checks the eight sample colors within one level. A separate check confirms black-point compensation does not change the distinct-profile sample for any intent. This oracle does not read rendered pixels, but may share LittleCMS algorithms with PDFium/Poppler; it is not an independent CMM implementation.
The matrix covers all four standard intents, with the declared default and override expectations preserved:
- `ri` and ExtGState `/RI`; nested `q/Q` changes and restoration.
- Shared Form XObject inheritance through `ri` and `gs`; Form content `ri`/`gs` override; caller state restored after the Form returns.
- One Image XObject without `/Intent`, reused in forward/reverse intent order and with `gs` order Perceptual→Relative→Perceptual→Absolute. Image dictionary `/Intent` overrides the caller and does not change the following vector's state.
- Indexed ICC vector and image; stroking color; standard-font text; axial shading.
- Shading patterns inheriting the caller, and pattern ExtGState `/RI` override.
- Colored Type3 `d0` glyphs with rectangles or images, reusing the same font and charcode 65 under four caller intents, plus glyph-content `ri` override.
Type3 glyph probe points lie inside a large filled rectangle. Standard-font text samples the interior of the Helvetica-Bold `H` stem. Shading expectations account for the actual sampled raster pixel center. The corpus does not cover unknown intent names, malformed intent types, soft-mask luminosity/compositing, tiling patterns, real printing profiles, arbitrary ICC profiles, physical displays, Windows or human-approved golden images.
## Generate and validate
Use Python with pypdf and Pillow; validation also needs a shared LittleCMS2 library. Full comparisons require qpdf, pdftoppm and the project's `pdf-worker-evidence`/`docview-pdf-worker` binaries. A fresh output directory is mandatory.
```sh
python3 tests/fixtures/pdf/generate_rendering_intents.py --output /path/to/new-corpus
python3 tests/cmyk_lut/intents.py --self-check --output /path/to/new-self-check
python3 tests/cmyk_lut/intents.py --build-dir build \
--pdfium-library /path/to/selected/libpdfium.so \
--scales 0.5 1 2 --output /path/to/new-comparison
```
`--corpus` selects a newly generated corpus if needed. `--pdfium-library` prepends its directory to the child's library path, verifies the actual `ldd` resolution before rendering, and records its hash; an RPATH selection mismatch fails. The normal worker sandbox and font broker remain active. The script does not replace any installed library.
`--self-check` exits successfully after validating the fixture/CMM, but deliberately records `success:false` and `renderingAcceptance:false`: it is not a rendering pass. A full report records PDFium and Poppler results separately; overall success currently requires both renderers, all probes and unchanged inputs/binaries. A failed comparison retains every probe and its exact CMM error, command logs, hashes and comparison images. The tolerance is not relaxed for another renderer's discrepancy.
During initial 1× validation, the fixed unmodified PDFium baseline failed 150/200 probes, consistently exposing its Perceptual-only conversion. Poppler 26.05.0 matched 194/200; the six failures were confined to shading-pattern ExtGState `/RI` override, where its color matched the caller intent. These are diagnostic observations, not acceptance of either mismatch. Final patched-renderer results belong in separate evidence directories. Independent regeneration reproduced all four generated files byte-for-byte.
References: [ISO 32000-1, clauses 8.4, 8.6.5.8, 8.7.4, 8.9.5, 8.10 and 9.6.5](https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf), [ICC v2 specification](https://archive.color.org/files/icc32.pdf), [LittleCMS](https://www.littlecms.com/).
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
+102
View File
@@ -0,0 +1,102 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R /Outlines 8 0 R /PageLabels << /Nums [0 << /S /r >> 1 << /S /D /St 1 >>] >> /StructTreeRoot 11 0 R /MarkInfo << /Marked true >> /AcroForm << /Fields [16 0 R] /DR << /Font << /F1 7 0 R >> >> /DA (/F1 12 Tf 0 g) >> /Names << /Dests << /Names [(second) [4 0 R /XYZ 40 200 null]] >> >> >>
endobj
2 0 obj
<< /Type /Pages /Kids [3 0 R 4 0 R] /Count 2 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 240 260] /CropBox [20 30 220 230] /Resources << /XObject << /Fm 20 0 R >> /Font << /F1 7 0 R >> >> /Contents 5 0 R /StructParents 0 /Annots [14 0 R 15 0 R 16 0 R 18 0 R] >>
endobj
4 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Rotate 90 /Resources << /Font << /F1 7 0 R >> >> /Contents 6 0 R >>
endobj
5 0 obj
<< /Length 82 >>
stream
0 g /Chapter <</MCID 0>> BDC BT /F1 16 Tf 60 180 Td (Heading One) Tj ET EMC /Fm Do
endstream
endobj
6 0 obj
<< /Length 49 >>
stream
BT /F1 20 Tf 40 100 Td (Second Page Needle) Tj ET
endstream
endobj
7 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
8 0 obj
<< /Type /Outlines /First 9 0 R /Last 10 0 R /Count 2 >>
endobj
9 0 obj
<< /Title (First heading) /Parent 8 0 R /Dest [3 0 R /XYZ 60 180 null] /Next 10 0 R >>
endobj
10 0 obj
<< /Title (Named second) /Parent 8 0 R /Dest (second) /Prev 9 0 R >>
endobj
11 0 obj
<< /Type /StructTreeRoot /K [12 0 R 13 0 R] /RoleMap << /Chapter /H1 >> /ParentTree << /Nums [0 [12 0 R 13 0 R 13 0 R]] >> >>
endobj
12 0 obj
<< /Type /StructElem /S /Chapter /T (Original Heading) /P 11 0 R /Pg 3 0 R /K 0 >>
endobj
13 0 obj
<< /Type /StructElem /S /H2 /P 11 0 R /Pg 3 0 R /K [1 2] >>
endobj
14 0 obj
<< /Type /Annot /Subtype /Link /Rect [30 30 90 45] /A << /S /URI /URI (https://example.org/) >> >>
endobj
15 0 obj
<< /Type /Annot /Subtype /Link /Rect [100 30 160 45] /A << /S /Launch /F (/tmp/never-execute) >> >>
endobj
16 0 obj
<< /Type /Annot /Subtype /Widget /FT /Tx /T (ReadonlyField) /V (Saved) /Ff 1 /F 4 /Rect [120 60 160 90] /P 3 0 R /AP << /N 17 0 R >> >>
endobj
17 0 obj
<< /Length 23 /Type /XObject /Subtype /Form /BBox [0 0 40 30] /Resources << >> >>
stream
1 0 0 rg 0 0 40 30 re f
endstream
endobj
18 0 obj
<< /Type /Annot /Subtype /Text /Rect [180 200 200 220] /Contents (Read-only comment) /F 4 >>
endobj
19 0 obj
<< /Title (DocView PDF fixture) /Author (DocView tests) >>
endobj
20 0 obj
<< /Length 76 /Type /XObject /Subtype /Form /BBox [0 0 240 260] /Resources << /Font << /F1 7 0 R >> >> >>
stream
/H1 <</MCID 0>> BDC BT /F1 12 Tf 50 50 Td (Different Form Heading) Tj ET EMC
endstream
endobj
xref
0 21
0000000000 65535 f
0000000015 00000 n
0000000346 00000 n
0000000409 00000 n
0000000641 00000 n
0000000778 00000 n
0000000911 00000 n
0000001011 00000 n
0000001081 00000 n
0000001153 00000 n
0000001255 00000 n
0000001340 00000 n
0000001482 00000 n
0000001581 00000 n
0000001657 00000 n
0000001772 00000 n
0000001888 00000 n
0000002040 00000 n
0000002179 00000 n
0000002288 00000 n
0000002363 00000 n
trailer
<< /Size 21 /Root 1 0 R /Info 19 0 R >>
startxref
2579
%%EOF

Some files were not shown because too many files have changed in this diff Show More