Phase 3 (Organize + robust save) + Phase 4 (Edit content); update docs

Engine:
- organize.rs: build_document(plan) core — insert/delete/rotate/crop/extract/merge/split
- watermark.rs: watermark + header/footer via PdfPages::watermark, CID Unicode fonts
- qpdf.rs: QPDF CLI wrapper — repair corrupt files, re-encrypt after edits, ensure_openable
- edit.rs: MOAT — list_objects + apply_edits (SetText VN, Transform, Delete, Add/ReplaceImage)
- Tests: organize/watermark/qpdf_safety/edit roundtrip — 43/43 engine tests green

UI (Tauri): "Tổ chức trang" mode (grid + drag-reorder + multi-select), "Sửa nội dung"
mode (WYSIWYG object overlay, edit-in-place), global undo/redo, robust file open.

Corpus: add encrypted.pdf + corrupt-truncated.pdf fixtures.

Docs: mark Phase 1-4 done in roadmap; document QPDF setup + engine module layout in
05-dev-setup; add 10-13 phase summaries & user-test checklists; README status.
This commit is contained in:
2026-07-14 22:07:38 +07:00
parent 274012f854
commit e442a9f678
26 changed files with 3924 additions and 40 deletions
+72
View File
@@ -0,0 +1,72 @@
%PDF-1.7
%¿÷¢þ
1 0 obj
<< /Extensions << /ADBE << /BaseVersion /1.7 /ExtensionLevel 8 >> >> /Outlines 2 0 R /Pages 3 0 R /Type /Catalog >>
endobj
2 0 obj
<< /Count 3 /First 4 0 R /Last 5 0 R /Type /Outlines >>
endobj
3 0 obj
<< /Count 3 /Kids [ 6 0 R 7 0 R 8 0 R ] /Type /Pages >>
endobj
4 0 obj
<< /Dest [ 6 0 R /Fit ] /Next 9 0 R /Parent 2 0 R /Title <5cfda9dc41ad5c1510ea99b8f3dd8cb47630e4894c742753f0e442af92c89a2e> >>
endobj
5 0 obj
<< /Dest [ 8 0 R /Fit ] /Parent 2 0 R /Prev 9 0 R /Title <fbedf1b46fa1d0014513c989f9b6efaababfeac5695dc976076c21f242fb94cf> >>
endobj
6 0 obj
<< /Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 11 0 R >> >> /Type /Page >>
endobj
7 0 obj
<< /Contents 12 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 11 0 R >> >> /Type /Page >>
endobj
8 0 obj
<< /Contents 13 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 11 0 R >> >> /Type /Page >>
endobj
9 0 obj
<< /Dest [ 7 0 R /Fit ] /Next 5 0 R /Parent 2 0 R /Prev 4 0 R /Title <8bce9f40a0e13e698de5e8cbfb65f674327aa79759ee3e060c955133432fd1fd> >>
endobj
10 0 obj
<< /Length 112 /Filter /FlateDecode >>
stream
x5ë„ðç·`9ñ�ƒxH±õ²ÙÃ蜓d )W@8d¹ÅÎÇæEúæ„wW¤oË_r—ЕŒç¼®e÷qZ?”yD�Ä/ôá[l&•i!„bç#¬ëvN¡t˜ˆ-ã1€tËÑv:Ê–È=endstream
endobj
11 0 obj
<< /BaseFont /Helvetica /Subtype /Type1 /Type /Font >>
endobj
12 0 obj
<< /Length 96 /Filter /FlateDecode >>
stream
Ù [ç,äæ½4k‹ß�1ù`c܆þÿç�®=qg†Þ†!ñä7MôîbõTŒaÙ>ñ
Ó£›(N;?{ú6êîŒ×Â? ªÎ”›¡¤ôe­!îè'8vl9Tº-Ô;î¡9endstream
endobj
13 0 obj
<< /Length 80 /Filter /FlateDecode >>
stream
‰áÛþÓu�Õîd␍‘ÙyFÔŒ␍`ÓQ%‹t~™¸¿õŠ–![ôM¾,ÂzÁ—{¤:º¼Hö*†8ã�Éš1f†0£œ¡bnÓ*2�>F©¬�v�¼endstream
endobj
14 0 obj
<< /CF << /StdCF << /AuthEvent /DocOpen /CFM /AESV3 /Length 32 >> >> /Filter /Standard /Length 256 /O <729b37e1523893a80350fc0adc0899599e71059fc8a526122056d53ab29f6eb4fa241f9de0d3d24e17613bf36d76fb8c> /OE <6183208bd3e782306e0f2cdf908823625931b449fd64048833f3232bed06fb5f> /P -4 /Perms <3b2517f4428945cddeb0cc6fdf0f12b5> /R 6 /StmF /StdCF /StrF /StdCF /U <6416d3fecc061e6b27f23dd8fcb0bb06597312e5b444e1b87db30721196a04400045559b493f6f8a19d6bc4df0da8c5e> /UE <97c8e67034f218a724c0c13e3cc846a29293cc3e8eed182cd1130edb8a4dd549> /V 5 >>
endobj
xref
0 15
0000000000 65535 f
0000000015 00000 n
0000000146 00000 n
0000000217 00000 n
0000000288 00000 n
0000000430 00000 n
0000000572 00000 n
0000000702 00000 n
0000000832 00000 n
0000000962 00000 n
0000001116 00000 n
0000001300 00000 n
0000001371 00000 n
0000001538 00000 n
0000001689 00000 n
trailer << /Root 1 0 R /Size 15 /ID [<8e41f82b9afc8df9d8276f2a629270aa><8e41f82b9afc8df9d8276f2a629270aa>] /Encrypt 14 0 R >>
startxref
2237
%%EOF