Commit Graph
1330 Commits
Author SHA1 Message Date
bflatastic cea263ddbf Merge #6219: M11: PDF/A verify reports pages with transparency but no blending colour space, and blend modes ISO 32000-1 doesn't define (optimize.pdfa-validate)
# Conflicts:
#	crates/preflight/src/lib.rs
#	crates/preflight/src/tests.rs
#	parity/acrobat-features.toml
2026-11-09 08:12:33 +07:00
bflatastic b3a5ac3ac1 Merge #6215: M11: PDF/A verify reports SetState, NOP and Named actions other than the four page moves (optimize.pdfa-validate)
# Conflicts:
#	crates/preflight/src/tests.rs
#	parity/acrobat-features.toml
2026-11-09 08:11:26 +07:00
bflatastic 6be3850177 Merge #6214: M11: PDF/A verify checks the file identifier and Save as PDF/A adds one (optimize.pdfa-validate)
# Conflicts:
#	crates/automation/src/tools.rs
#	crates/cos/src/lib.rs
#	crates/preflight/src/lib.rs
#	crates/preflight/src/tests.rs
#	parity/acrobat-features.toml
2026-11-09 08:10:01 +07:00
bflatastic 174d0b31e8 Merge #6207: M11: PDF/A verify reports transfer functions, halftones and rendering intents a graphics state may not use (optimize.pdfa-validate)
# Conflicts:
#	crates/preflight/src/lib.rs
#	crates/preflight/src/tests.rs
#	parity/acrobat-features.toml
2026-11-09 08:08:08 +07:00
bflatastic e2417e1561 Merge #6206: M11: PDF/A verify checks the file header and Save as PDF/A rewrites it (optimize.pdfa-validate)
# Conflicts:
#	crates/preflight/src/tests.rs
#	parity/acrobat-features.toml
2026-11-09 08:07:05 +07:00
bflatastic fd204ced66 Merge #6203: M11: PDF/A verify reports Separation spaces of one name that differ and DeviceN spot colours missing from /Colorants (optimize.pdfa-validate)
# Conflicts:
#	crates/preflight/src/lib.rs
#	crates/preflight/src/tests.rs
#	parity/acrobat-features.toml
2026-11-09 08:05:52 +07:00
bflatastic 25ac77c360 Merge #6202: M11: PDF/A verify reports integers, reals, strings, names, CIDs and page boundaries past the implementation limits (optimize.pdfa-validate)
# Conflicts:
#	crates/preflight/src/lib.rs
#	parity/acrobat-features.toml
2026-11-09 08:04:54 +07:00
bflatastic 4dc55320bc Merge #6254: M11: PDF/A verify checks that XMP extension schema descriptions are complete (optimize.pdfa-validate) 2026-11-09 08:02:53 +07:00
bflatastic dee86eecc1 Merge #6232: M11: PDF/A verify checks that TIFF, EXIF and aux XMP properties have their value types (optimize.pdfa-validate)
# Conflicts:
#	crates/preflight/src/tests.rs
#	crates/preflight/src/xmp_types.rs
#	parity/acrobat-features.toml
2026-11-09 08:02:44 +07:00
mtlcl410 d65ae4268e M6: a calculate script that sets its own field through the field object keeps that value (form.custom-scripts) (#6616) 2026-11-09 08:59:19 +08:00
mtlcl410 87bc00a991 M3: Find matches words divided by soft hyphens, zero width characters or a Chinese or Japanese line end (view.find) (#6595) 2026-11-09 08:58:34 +08:00
mtlcl410 b9ffb68b12 M6: a product of empty fields is 0, not 1 (form.af-simple-calculate) (#6567) 2026-11-09 08:57:28 +08:00
mtlcl410 3e48317ae3 M10: Pages per sheet takes a custom grid of columns by rows (#6551) (#6559) 2026-11-09 08:57:06 +08:00
Oliver H. 616f245b04 fix(edit): break the row on every Unicode row break (#6295) 2026-11-09 08:54:37 +08:00
mtlcl410 4f97a22a2e Merge remote-tracking branch 'upstream/main' into lane6-6215
# Conflicts:
#	crates/preflight/src/tests.rs
#	parity/acrobat-features.toml
2026-11-09 08:54:02 +08:00
quincy-jc 25aef86a1d feat(reduce): ask where to save before compressing (#6229) 2026-11-09 08:53:12 +08:00
mtlcl410andClaude Opus 5.5 2b0fdedffb Merge upstream/main into fix/pdfa-implementation-limits
Resolve conflicts with the XMP value-type checks (6.6.2.3.1): keep both
sets of tests, and combine the pdfa-verify parity evidence and notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-09 08:52:16 +08:00
mtlcl410andClaude Opus 5.5 8c2ef13de6 Merge upstream/main into fix/pdfa-separation-devicen
Resolve conflicts with the XMP value-type checks (6.6.2.3.1): keep both
sets of tests, and combine the pdfa-verify parity evidence and notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-09 08:50:28 +08:00
mtlcl410 608ff62dae M6: a widget whose /Parent names a missing object is a field of its own (form.field-list) (#6445) 2026-11-09 08:49:56 +08:00
mtlcl410 de7ed00a1a M3: End shows the end of the document, the last page down to its bottom (view.page-navigation) (#6435) 2026-11-09 08:49:35 +08:00
Ken Mantle 218c2bb21f M12: headless orbit navigation for 3D models (#6406) 2026-11-09 08:48:58 +08:00
mtlcl410 e6b6216fd9 M1: a V4 RC4 file with a 40- or 48-bit key reads and saves (#6397) (#6398) 2026-11-09 08:48:43 +08:00
mtlcl410 1a28606c64 M10: a layer the document marks screen-only stays off the printed sheet (print.print-ready-pdf) (#6387) 2026-11-09 08:48:28 +08:00
BFlat 53eec5cd24 Merge pull request #6502 from mtlcl410/fix/sign-string-bytes-not-spelling
M9: a signed string respelled in hexadecimal is no change after signing (sign.changes-after-signing)
2026-11-09 08:48:07 +08:00
mtlcl410 0a029f0aad M12: floating fields show the values scripts give them, and the sheet number and count (#6160) (#6166) 2026-11-09 08:45:03 +08:00
Harrison Booth 3b731f9458 Expose widget rectangles to field scripts (#6093) 2026-11-09 08:42:39 +08:00
Hasan N. bf409db55c M3: pages shorter than the window sit in its middle (#5708) (#5759) 2026-11-09 08:38:40 +08:00
mtlcl410 6062cd6a44 M5: Replace Text keeps its replacement on the group's primary, the caret (comment.replace-text) (#5689) 2026-11-09 08:38:25 +08:00
mtlcl410 ee2398f710 M11: PDF/A verify checks that predefined XMP properties have their value types (optimize.pdfa-validate) (#6220) 2026-11-09 08:37:56 +08:00
3ae9093d61 M2: info lists the repairs made while opening, as Document Properties does (misc.cli-inspect) (#6518)
* M2: `info` lists the repairs made while opening, as Document Properties does (misc.cli-inspect)

`pdfcraft-cli info` now prints a `repairs` array: the notes about damage
repaired while opening that the app shows in Document Properties and
doc_info reports. It opens the document as the app does, once (the session
the dynamic XFA summary already used), so notes the app adds after reading
the objects, such as a page tree rebuilt from the pages found by scanning,
are listed too. A file the app cannot open for editing falls back to what
reading its objects repaired; a sound file prints an empty array.

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

* M2: `info` runs none of the document's scripts while inspecting it (misc.cli-inspect)

The session `info` opens to read the app's repair notes and the dynamic XFA
layout now has JavaScript turned off, so an XFA form's initialize and
calculate scripts, which the app runs on opening, do not run during
inspection of an untrusted file. Before this branch the session was opened
for dynamic XFA forms only, and their scripts ran there too.

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

* M2: `info` reads the standards and repairs from the session it opens, and a laid-out form keeps its repair notes (misc.cli-inspect)

`info` now takes the declared standards (`Document::standards`, as the
Standards panel reads them) and the repair notes from the session it
opened, and reads the file once more only when the app cannot open it.
When opening lays out a dynamic XFA form, or writes any other revision,
the notes about damage repaired while reading the file now stay with the
re-read document, so Document Properties and `info` both list them.

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

---------

Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 08:30:37 +08:00
42b21e5362 fix(render): a form XObject that draws itself is drawn once (hayro-interpret patch 89) (#6515)
* M2: a form XObject that draws itself is drawn once (hayro-interpret patch 89)

A form whose content names itself, directly or through another form, a
pattern or a glyph, drew itself again at every level until the page's
nested-paint budget (50,000) ran out. PDFBOX-5782's poppler-748 page 2,
whose form names a /Pages dictionary as /X0 and so finds itself in the
page's resources, took 38 s.

hayro-interpret now keeps the forms being drawn on the context and skips
a form already on it, reporting ContentTruncated (ISO 32000-2 §8.10.1: a
form is a self-contained description). The lenient fallback from a form's
own resources to the page's stays: MuPDF, Poppler and PDFium all draw a
name from the page's resources when the form's /Resources has no
XObject subdictionary (MuPDF and Poppler also when it has an empty one).

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

* fix(render): a form that reaches itself through a pattern or a glyph is drawn once (hayro-interpret patch 89)

The forms being drawn are now kept per page and thread rather than per
context, so the tiling patterns, Type 3 glyphs, soft masks and groups
painted inside a form, which hayro interprets in contexts of their own,
see that the form is being drawn and skip it inside themselves. A form
drawn again after it has finished draws as before.

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

* chore: re-run CI after the Fill & Sign save comparison failed on the clock (#6066)

`fill_sign_enter_adds_lines_outside_click_commits_and_escape_cancels`
compares two saves whose /ModDate fell in different seconds; it passes
locally on this commit. No change.

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

---------

Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 08:30:14 +08:00
9b231f241d perf(render): undo TIFF predictor 2 a byte row at a time at 8 and 16 bits (#6505)
TIFF predictor 2 (ISO 32000-2 §7.4.4.4, Table 10) went through the
bit-level BitChunks/BitWriter path for every bit depth, re-reading the
previous output pixel through a new BitReader per pixel. Whole-byte
samples (8 and 16 bits per component) are now undone on byte slices,
each sample added to the same component of the pixel to its left,
wrapping at its width; 1-, 2- and 4-bit samples keep the bit-level path.
The output is byte-identical, including the dropped partial last row.

A page of 45 full-page 8-bit grey images so predicted (PDFBOX-1350)
renders in about 4 s instead of 23 s with the same pixels.

Vendored hayro-syntax patch 42.


Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn

Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 08:29:44 +08:00
b07a84f003 M5: a comment whose colour is written [r g b null] is drawn, as CMYK with the null read as 0 (view.render-annotation-appearances) (#6503)
* M5: a comment whose colour is written [r g b null] is drawn, as CMYK with the null read as 0 (view.render-annotation-appearances)

ISO 32000-2 Table 166 /C (and /IC, Tables 178, 180, 181; /MK /BC and /BG,
Table 192) is an array of 0, 1, 3 or 4 numbers whose length picks the
colour space. A four-entry array with a non-number in it, such as
[1 0 0 null] (PDFBOX-2699), made the /C parser give up, so a shape
without an appearance stream was not drawn at all. PDFium, MuPDF and
Poppler all read such an array as CMYK with the non-number as 0.

- annot: a four-entry /C or /IC reads non-numbers as 0; other lengths
  still need every entry to be a number.
- annot: the properties' fill uses the same parser (it read
  [r g b null] as RGB before), and /C no longer drops a non-number
  to make three numbers.
- forms: /MK /BC and /BG read a four-entry array the same way instead
  of dropping the non-number and drawing RGB.

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

* M5: comment properties report the stroke colour as drawn; a reference among four colour entries is not read as 0 (view.render-annotation-appearances)

props() reads a non-FreeText /C through the appearance parser, so a
[1 0 0 null] stroke reports CMYK cyan as drawn, and grey and CMYK
strokes report their converted colour. A reference among the four
entries of a /C array (ISO 32000-2 7.3.10) is left unreadable instead
of standing in as 0, so /C [1 0 0 6 0 R] is never drawn cyan.

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

* M5: re-run CI (fill_sign Escape test depends on the clock's second, passes locally)

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

* M5: the comment list reports a comment's colour as drawn (view.render-annotation-appearances)

summaries() accepted only a three-entry /C, so a Square with /C [1 0 0 null],
drawn cyan and reported cyan by props(), had no colour in the comment list;
grey and CMYK colours were dropped the same way. Non-FreeText comments now
read /C through drawn_color (the array itself followed when it is given by
reference), keeping the three-number fallback and the FreeText /DA handling.

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

* M5: the render inspector lists a comment's colour as drawn (view.render-annotation-appearances)

The inspector accepted only a three-entry /C, with a referenced entry read
as 0, so a /C [1 0 0 null], a grey or a CMYK colour listed none, unlike the
comment list and the drawing. Non-FreeText comments now read /C by the
appearance builder's rule (one entry grey, four CMYK with a non-number as 0
and a reference unreadable, finite and clamped), with the three-number
fallback reading referenced entries.

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

---------

Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 08:29:31 +08:00
BFlat 8d5d39ef5e Combine files: a drop is one undo step, in order, and names what it can't take (#6645)
* Combine files: add a drop as one step, in order, and name what it can't take

Files dropped on the Combine files tab are handled as one batch: they join
the end of the list in the order dropped, as one undo step, from their path
or, when a drop carries only bytes, from those. A folder still adds the
files in it and its subfolders. Files of a kind Combine doesn't take are
left out and named in a notice, instead of joining the list as files that
can't be read. In a browser the dropped files are read one after another,
so they keep their order too.

* Combine files: let the web build use Incoming for dropped files

* Parity: Combine files takes drops in order, as one step, and names what it leaves out
2026-11-09 04:10:08 +08:00
BFlat 71aa9027d3 Merge pull request #6643 from storytold/merge/5404-export-paragraphs
Exports keep a wrapped paragraph and a bulleted list as paragraphs (#5404, merged with main)
2026-11-09 04:09:08 +08:00
BFlat 43f24aa169 Draw Thai in Fill & Sign, text boxes, form fields, headers, footers and watermarks (#6632)
Refs #2354. Thai typed into these tools is shaped and drawn from the Thai face through Add text's writer (now pdfcraft_fonts::shaped_text), searchable and copyable, instead of being written as ?????; a build without a Thai face refuses it with a message.
2026-11-09 02:56:34 +08:00
BFlat e0f90d5f2d Edit a PDF: select all, copy, cut and paste page objects within and between documents (#6639)
Refs #5989. Ctrl/Cmd+A selects every object on the page; copied objects paste as page content that draws the same, within a document or into another, with organize's bounded deep copy across documents. Headless: object_copy, object_paste, object_move all.
2026-11-09 02:32:50 +08:00
BFlat c07e092ff5 Merge pull request #6637 from storytold/merge/3492-thai-line-breaks
M7: break Thai rows between dictionary words (#3492, merged with main)
2026-11-09 02:25:04 +08:00
bflatastic 70fd3ec969 Parity: Word export names the poem-only page among the joins it gets wrong
A page whose only text is short unpunctuated lines takes its longest
line for the right edge, so those lines join into one paragraph.
2026-11-09 01:18:57 +07:00
bflatastic 79e260f949 Merge #5404: exports keep a wrapped paragraph and a bulleted list as paragraphs
Resolved against main's ruled tables (#5154, #6626) and clipboard export:
the new tests pass main's rules argument to tables(), and the parity
notes keep both sides' wording.
2026-11-09 01:13:17 +07:00
bflatastic f6831d58ea Merge remote-tracking branch 'origin/main' into merge/3492-thai-line-breaks 2026-11-09 00:15:27 +07:00
bflatastic 8f5a5aeb89 Merge remote-tracking branch 'origin/main' into fix/thai-grouped-text-v2
# Conflicts:
#	docs/roadmap.md
2026-11-09 00:13:03 +07:00
BFlat da6ee1e62a Merge pull request #6634 from storytold/merge/1641-web-ocr
OCR in the web build (#1641, merged with main, two fixes)
2026-11-09 01:10:19 +08:00
BFlat c659211308 Merge pull request #6633 from storytold/merge/5454-ocr-phrase-size
An edited OCR phrase is drawn at one size (#5454, with the requested test)
2026-11-09 01:10:11 +08:00
bflatastic c8248e3b6d Merge #3492: M7: break Thai rows between dictionary words
Brings the Thai word-breaking branch up to date with main. The only conflict was the edit.add-text parity entry: main's evidence and notes (print inks) are kept, with the new Thai test added and the Thai wrapping sentence updated.
2026-11-08 23:58:18 +07:00
BFlat 485bc143a9 Merge pull request #6631 from storytold/merge/5498-word-export-language
Word and HTML exports name the document's language (#5498, merged with main)
2026-11-09 00:57:18 +08:00
bflatastic 8afe3f4f67 Merge remote-tracking branch 'origin/main' into fix/thai-grouped-text-v2
# Conflicts:
#	ROADMAP.md
2026-11-08 23:56:10 +07:00
bflatastic 2f492db9a3 Merge remote-tracking branch 'origin/main' into merge/5454-ocr-phrase-size 2026-11-08 23:39:29 +07:00
bflatastic 6bc6d80279 Merge remote-tracking branch 'origin/main' into merge/1641-web-ocr 2026-11-08 23:38:03 +07:00
bflatastic 1ea1c63f3d Merge remote-tracking branch 'origin/main' into merge-5498
# Conflicts:
#	parity/acrobat-features.toml
2026-11-08 23:33:35 +07:00