@laminapdf/wasm 0.2.0-alpha.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,16 +44,151 @@ export type PageLinkJs = {
44
44
  } & LinkToJs;
45
45
 
46
46
 
47
+ /**
48
+ * A bookmark's look: its colour (`/C`; `None` is the viewer's default, black) and type style
49
+ * (`/F`: bit 1 italic, bit 2 bold).
50
+ *
51
+ * Added in 0.3.0.
52
+ */
53
+ export interface OutlineStyle {
54
+ /**
55
+ * The colour.
56
+ */
57
+ color?: string | null;
58
+ /**
59
+ * Bold.
60
+ */
61
+ bold?: boolean;
62
+ /**
63
+ * Italic.
64
+ */
65
+ italic?: boolean;
66
+ }
67
+
68
+ /**
69
+ * A change a signature's restriction forbids.
70
+ */
71
+ export interface ViolationJs {
72
+ /**
73
+ * The kind of change.
74
+ */
75
+ class: ModificationClass;
76
+ /**
77
+ * `docMdp`, `fieldMdp`, `usageRights`, `signedBytes` or `signedWidget`.
78
+ */
79
+ restriction: string;
80
+ /**
81
+ * The certification's `/P` (1, 2 or 3), for a `docMdp` restriction.
82
+ */
83
+ permission?: number;
84
+ /**
85
+ * The signature that carries the restriction.
86
+ */
87
+ signature: SignatureJs;
88
+ /**
89
+ * The form field whose widget a page edit deletes or reshows (its ID), for a
90
+ * `signedWidget` restriction or a `fieldMdp` one that a page edit breaks.
91
+ */
92
+ field?: string;
93
+ }
94
+
47
95
  /**
48
96
  * A colour for text options (the text module's records).
49
97
  */
50
98
  export type ColorInit = number[] | string;
51
99
 
100
+ /**
101
+ * A colour of 8 bits a channel, `"#rrggbb"` on the wire. A bookmark's `/C` (§12.3.3,
102
+ * Table 151) holds it as three numbers from 0 to 1.
103
+ *
104
+ * Added in 0.3.0.
105
+ */
106
+ export type Rgb = string;
107
+
108
+ /**
109
+ * A conformance claim the document's metadata no longer meets.
110
+ *
111
+ * Added in 0.2.0.
112
+ */
113
+ export type ConformanceWarning = { code: "pdfa-one-author"; authors: number } | { code: "pdfua-title-missing" } | { code: "pdfa-info-mismatch"; keys: MetadataKey[] } | { code: "duplicate-tags-incomplete" } | { code: "imported-tags-dropped" } | { code: "imported-pdfa-unchecked" };
114
+
52
115
  /**
53
116
  * A conformance profile.
54
117
  */
55
118
  export type ProfileInit = "PDF/UA-1" | "PDF/A-2b" | "PDF/A-2u" | "PDF/A-3b";
56
119
 
120
+ /**
121
+ * A document's metadata as one record, read from the Info dictionary and the XMP packet.
122
+ *
123
+ * When the two disagree, the values come from the XMP packet in a PDF 2.0 file (ISO 32000-2
124
+ * §14.3.3 deprecates the Info entries) or a file that claims PDF/A (whose packet is
125
+ * authoritative, ISO 19005-2 §6.6.2.3.1), and otherwise from the side whose modification date
126
+ * is newer, Info winning a tie. A field the winning side lacks is taken from the other.
127
+ * [`disagreements`](DocumentMetadata::disagreements) names the fields where the two differ, so
128
+ * a properties view can say so.
129
+ *
130
+ * Added in 0.2.0.
131
+ */
132
+ export interface DocumentMetadata {
133
+ /**
134
+ * The title.
135
+ */
136
+ title?: string;
137
+ /**
138
+ * The authors, in order (Info's `/Author` split at `;`).
139
+ */
140
+ authors: string[];
141
+ /**
142
+ * The subject.
143
+ */
144
+ subject?: string;
145
+ /**
146
+ * The keywords.
147
+ */
148
+ keywords?: string;
149
+ /**
150
+ * The application the content came from.
151
+ */
152
+ creator?: string;
153
+ /**
154
+ * The application that wrote the PDF.
155
+ */
156
+ producer?: string;
157
+ /**
158
+ * The creation date (a PDF date string on the wire).
159
+ */
160
+ created?: string;
161
+ /**
162
+ * The modification date.
163
+ */
164
+ modified?: string;
165
+ /**
166
+ * Which side the values come from.
167
+ */
168
+ source: MetadataSource;
169
+ /**
170
+ * The fields where Info and XMP hold different values.
171
+ */
172
+ disagreements: MetadataKey[];
173
+ /**
174
+ * What `/Metadata` holds.
175
+ */
176
+ packet: PacketStatus;
177
+ /**
178
+ * The PDF/A part and conformance the packet claims (`pdfaid:`), e.g. `"2B"`.
179
+ */
180
+ pdfa?: string;
181
+ /**
182
+ * The PDF/UA part the packet claims (`pdfuaid:part`).
183
+ */
184
+ pdfua?: number;
185
+ /**
186
+ * In a PDF 2.0 file, the Info entries besides the two dates: deprecated, kept as they
187
+ * were for older readers, and never written by an edit.
188
+ */
189
+ keptInfoKeys: MetadataKey[];
190
+ }
191
+
57
192
  /**
58
193
  * A document's properties, for a properties view.
59
194
  */
@@ -231,12 +366,33 @@ export interface TextLinkInit {
231
366
  * ```
232
367
  *
233
368
  * [ADR 0006]: https://github.com/laudebugs/laminapdf/blob/main/docs/decisions/0006-op-log-and-undo.md
369
+ *
370
+ * Added in 0.2.0.
234
371
  */
235
372
  export interface OpLog {
236
373
  v: 1;
237
374
  ops: Op[];
238
375
  }
239
376
 
377
+ /**
378
+ * A metadata field Lamina PDF keeps in step in the Info dictionary and the XMP packet: what
379
+ * [`RemoveMetadata`] removes and [`DocumentMetadata::disagreements`] names.
380
+ *
381
+ * | Key | Info | XMP |
382
+ * | --- | --- | --- |
383
+ * | `title` | `/Title` | `dc:title` |
384
+ * | `authors` | `/Author` (joined with `; `) | `dc:creator` |
385
+ * | `subject` | `/Subject` | `dc:description` |
386
+ * | `keywords` | `/Keywords` | `pdf:Keywords` |
387
+ * | `creator` | `/Creator` | `xmp:CreatorTool` |
388
+ * | `producer` | `/Producer` | `pdf:Producer` |
389
+ * | `created` | `/CreationDate` | `xmp:CreateDate` |
390
+ * | `modified` | `/ModDate` | `xmp:ModifyDate` |
391
+ *
392
+ * Added in 0.2.0.
393
+ */
394
+ export type MetadataKey = "title" | "authors" | "subject" | "keywords" | "creator" | "producer" | "created" | "modified";
395
+
240
396
  /**
241
397
  * A model result the job waits for.
242
398
  */
@@ -281,6 +437,32 @@ export interface ModelInfoInit {
281
437
  licence: string;
282
438
  }
283
439
 
440
+ /**
441
+ * A move in user space (ISO 32000-2 §8.3.2.3: y up), in user-space units. Both distances are
442
+ * finite: [`Offset::new`] and the wire form refuse anything else, so a move never writes a
443
+ * coordinate a PDF can't hold.
444
+ *
445
+ * Added in 0.3.0.
446
+ */
447
+ export interface Offset {
448
+ dx: number;
449
+ dy: number;
450
+ }
451
+
452
+ /**
453
+ * A named destination brought in under another name.
454
+ */
455
+ export interface RenamedDestinationJs {
456
+ /**
457
+ * Its name in the source.
458
+ */
459
+ from: string;
460
+ /**
461
+ * Its name in this document.
462
+ */
463
+ to: string;
464
+ }
465
+
284
466
  /**
285
467
  * A page and how to show it.
286
468
  */
@@ -295,11 +477,60 @@ export interface TargetJs {
295
477
  view: TargetViewJs;
296
478
  }
297
479
 
480
+ /**
481
+ * A page of this document and how to show it: what `/Dest [page /XYZ …]` holds.
482
+ *
483
+ * Added in 0.3.0.
484
+ */
485
+ export interface ExplicitDestination {
486
+ /**
487
+ * The page.
488
+ */
489
+ page: string;
490
+ /**
491
+ * How to show it.
492
+ */
493
+ view: DestinationView;
494
+ }
495
+
298
496
  /**
299
497
  * A page-label numbering style.
300
498
  */
301
499
  export type LabelStyleInit = "decimal" | "upperRoman" | "lowerRoman" | "upperLetters" | "lowerLetters";
302
500
 
501
+ /**
502
+ * A patch of the window entries of `/ViewerPreferences` ([`WindowPreferences`]): each field
503
+ * left out keeps what the file has, `true` sets the entry, `false` removes it.
504
+ *
505
+ * Added in 0.3.0.
506
+ */
507
+ export interface WindowPreferencesPatch {
508
+ /**
509
+ * `/HideToolbar`.
510
+ */
511
+ hideToolbar?: boolean;
512
+ /**
513
+ * `/HideMenubar`.
514
+ */
515
+ hideMenubar?: boolean;
516
+ /**
517
+ * `/HideWindowUI`.
518
+ */
519
+ hideWindowUi?: boolean;
520
+ /**
521
+ * `/FitWindow`.
522
+ */
523
+ fitWindow?: boolean;
524
+ /**
525
+ * `/CenterWindow`.
526
+ */
527
+ centerWindow?: boolean;
528
+ /**
529
+ * `/DisplayDocTitle`.
530
+ */
531
+ displayDocTitle?: boolean;
532
+ }
533
+
303
534
  /**
304
535
  * A rectangle as returned to JavaScript.
305
536
  */
@@ -327,6 +558,24 @@ export interface RectJs {
327
558
  */
328
559
  export type RegionLabelName = "text" | "title" | "section-header" | "list-item" | "table" | "picture" | "caption" | "footnote" | "formula" | "page-header" | "page-footer" | "other";
329
560
 
561
+ /**
562
+ * A signature the planner found.
563
+ */
564
+ export interface SignatureJs {
565
+ /**
566
+ * `approval`, `certification`, `docTimeStamp` or `usageRights`.
567
+ */
568
+ kind: string;
569
+ /**
570
+ * The signature field's ID, when a field holds it.
571
+ */
572
+ field?: string;
573
+ /**
574
+ * The 1-based revision the signature closes, when known.
575
+ */
576
+ revision?: number;
577
+ }
578
+
330
579
  /**
331
580
  * A step's progress, and the model result the job waits for, if any.
332
581
  */
@@ -349,6 +598,60 @@ export interface ExtractProgressJs {
349
598
  request?: ModelRequestJs;
350
599
  }
351
600
 
601
+ /**
602
+ * Adds a bookmark under `parent` (`null`: the top level) at `at`, with its title, target and
603
+ * style. It has no children, so it has no open state yet (`/Count`, §12.3.3): set it with
604
+ * [`UpdateOutlineItem::open`] once it has some. The new item's ID is in
605
+ * [`Applied::created_outline_items`](crate::Applied::created_outline_items).
606
+ *
607
+ * On the wire: `{ "op": "addOutlineItem", "args": { "parent": null, "at": "last", "title":
608
+ * "Chapter 1", "target": { "destination": { "page": "p3.0", "view": { "kind": "fit" } } } } }`.
609
+ *
610
+ * Added in 0.3.0.
611
+ */
612
+ export interface AddOutlineItem {
613
+ /**
614
+ * The parent item; `None` for the top level.
615
+ */
616
+ parent?: string | null;
617
+ /**
618
+ * Where among the parent's children.
619
+ */
620
+ at: "first" | "last" | { before: string } | { after: string };
621
+ /**
622
+ * The title.
623
+ */
624
+ title: string;
625
+ /**
626
+ * Where the bookmark goes.
627
+ */
628
+ target: OutlineTarget;
629
+ /**
630
+ * Its colour and type style.
631
+ */
632
+ style?: OutlineStyle;
633
+ }
634
+
635
+ /**
636
+ * Adds a named destination, or points an existing one at `destination`. A name the catalog's
637
+ * `/Dests` dictionary holds stays there; any other goes into the `/Names /Dests` tree.
638
+ *
639
+ * On the wire: `{ "op": "setNamedDestination", "args": { "name": "results", "destination": {
640
+ * "page": "p7.0", "view": { "kind": "fitH", "top": 700 } } } }`.
641
+ *
642
+ * Added in 0.3.0.
643
+ */
644
+ export interface SetNamedDestination {
645
+ /**
646
+ * The name.
647
+ */
648
+ name: string;
649
+ /**
650
+ * Where it points.
651
+ */
652
+ destination: ExplicitDestination;
653
+ }
654
+
352
655
  /**
353
656
  * Alignment of a text box's lines.
354
657
  */
@@ -372,6 +675,47 @@ export interface WordInit {
372
675
  confidence: number;
373
676
  }
374
677
 
678
+ /**
679
+ * An XMP property declared in a PDF/A file's extension schemas.
680
+ */
681
+ export interface ExtensionPropertyJs {
682
+ /**
683
+ * The schema's namespace URI.
684
+ */
685
+ namespace: string;
686
+ /**
687
+ * The prefix the packet writes the namespace with.
688
+ */
689
+ prefix: string;
690
+ /**
691
+ * The property's local name.
692
+ */
693
+ name: string;
694
+ /**
695
+ * Its declared type, e.g. `Text` or `Seq Integer`.
696
+ */
697
+ valueType: string;
698
+ }
699
+
700
+ /**
701
+ * An annotation's own geometry, by `kind`; points are flat `[x, y, …]` lists in page space.
702
+ */
703
+ export type GeometryJs = { kind: "none" } | { kind: "quads"; quads: number[] } | { kind: "ink"; strokes: number[][] } | { kind: "vertices"; points: number[] } | { kind: "line"; points: number[] } | { kind: "callout"; points: number[] };
704
+
705
+ /**
706
+ * An article thread: its title and its parts in reading order.
707
+ */
708
+ export interface ThreadJs {
709
+ /**
710
+ * Its title (document text), when it has one.
711
+ */
712
+ title?: string;
713
+ /**
714
+ * Its parts.
715
+ */
716
+ parts: ThreadPartJs[];
717
+ }
718
+
375
719
  /**
376
720
  * An attached file's options.
377
721
  */
@@ -410,8 +754,149 @@ export interface AttachmentInit {
410
754
  * ```
411
755
  *
412
756
  * [ADR 0006]: https://github.com/laudebugs/laminapdf/blob/main/docs/decisions/0006-op-log-and-undo.md
757
+ *
758
+ * Added in 0.2.0.
759
+ */
760
+ export type Op = { op: "setInfo"; args: SetInfo } | { op: "rotatePage"; args: RotatePage } | { op: "setMetadata"; args: SetMetadata } | { op: "removeMetadata"; args: RemoveMetadata } | { op: "setInitialView"; args: SetInitialView } | { op: "addOutlineItem"; args: AddOutlineItem } | { op: "updateOutlineItem"; args: UpdateOutlineItem } | { op: "moveOutlineItem"; args: MoveOutlineItem } | { op: "deleteOutlineItem"; args: DeleteOutlineItem } | { op: "setNamedDestination"; args: SetNamedDestination } | { op: "renameNamedDestination"; args: RenameNamedDestination } | { op: "deleteNamedDestination"; args: DeleteNamedDestination } | { op: "setXmpProperty"; args: SetXmpProperty } | { op: "removeXmpProperty"; args: RemoveXmpProperty } | { op: "replaceXmpPacket"; args: ReplaceXmpPacket } | { op: "insertBlankPages"; args: InsertBlankPages } | { op: "deletePages"; args: DeletePages } | { op: "movePages"; args: MovePages } | { op: "rotatePages"; args: RotatePages } | { op: "reversePages"; args: ReversePages } | { op: "duplicatePages"; args: DuplicatePages } | { op: "insertPagesFrom"; args: InsertPagesFrom } | { op: "replacePages"; args: ReplacePages } | { op: "mergeDocuments"; args: MergeDocuments } | { op: "updateAnnot"; args: UpdateAnnot } | { op: "deleteAnnot"; args: DeleteAnnot } | { op: "setPageLabels"; args: SetPageLabels };
761
+
762
+ /**
763
+ * Changes a bookmark's title, target, style or open state. An absent field is left alone. A
764
+ * target held as another action (JavaScript, `Launch`, …) is replaced only when `target` is
765
+ * given; the item's other entries are kept.
766
+ *
767
+ * On the wire: `{ "op": "updateOutlineItem", "args": { "item": "o12.0", "title": "Results",
768
+ * "open": true } }`.
769
+ *
770
+ * Added in 0.3.0.
771
+ */
772
+ export interface UpdateOutlineItem {
773
+ /**
774
+ * The item.
775
+ */
776
+ item: string;
777
+ /**
778
+ * A new title.
779
+ */
780
+ title?: string;
781
+ /**
782
+ * A new target.
783
+ */
784
+ target?: OutlineTarget;
785
+ /**
786
+ * A new style (colour and type style together).
787
+ */
788
+ style?: OutlineStyle;
789
+ /**
790
+ * Open (children shown) or closed; a bookmark without children has nowhere to keep it
791
+ * (`/Count`, §12.3.3), so it writes nothing there.
792
+ */
793
+ open?: boolean;
794
+ }
795
+
796
+ /**
797
+ * Changes an annotation's common and markup entries and moves it.
798
+ *
799
+ * An absent field leaves the entry alone and `null` removes it. `translate` moves `/Rect` and
800
+ * the subtype's geometry (`/QuadPoints`, `/InkList`, `/Vertices`, `/L`, `/CL`) and the
801
+ * annotation's Popup with it, and keeps the appearance, which §12.5.5 maps onto the new
802
+ * `/Rect`. A `Locked` annotation refuses everything but a change of its flags and its
803
+ * contents; a `LockedContents` one refuses a change of its contents (`annotation-locked`).
804
+ * Widgets and annotations stored as direct dictionaries are refused (`annotation-not-editable`).
805
+ *
806
+ * On the wire: `{ "op": "updateAnnot", "args": { "id": "a12.0", "contents": "Checked",
807
+ * "translate": { "dx": 0, "dy": -10 } } }`.
808
+ *
809
+ * Added in 0.3.0.
810
+ */
811
+ export interface UpdateAnnot {
812
+ /**
813
+ * The annotation.
814
+ */
815
+ id: string;
816
+ /**
817
+ * `/Contents`: the comment, or the alternative description.
818
+ */
819
+ contents?: string | null;
820
+ /**
821
+ * `/T`: the author.
822
+ */
823
+ author?: string | null;
824
+ /**
825
+ * `/Subj`.
826
+ */
827
+ subject?: string | null;
828
+ /**
829
+ * `/M`, the modification date the edit writes.
830
+ */
831
+ modified?: string;
832
+ /**
833
+ * `/F`, all the flags at once (Table 167).
834
+ */
835
+ flags?: number;
836
+ /**
837
+ * A move in user space.
838
+ */
839
+ translate?: Offset;
840
+ }
841
+
842
+ /**
843
+ * Changes how the document asks to be shown when it opens. Each field is a patch: left out,
844
+ * it keeps what the file has; `null` removes the entry, so readers use their default; a value
845
+ * sets it.
846
+ *
847
+ * * `open`: the page and zoom to open at, written as an explicit destination in
848
+ * `/OpenAction` (§12.3.2.2). An `/OpenAction` that is an action other than `GoTo`
849
+ * (JavaScript, a named action, a link to another file) is never replaced or removed: the op
850
+ * fails with [`Error::OpenActionNotDestination`].
851
+ * * `page_mode`, `page_layout`: the panel to show and how to lay the pages out.
852
+ * * `preferences`: the window entries of `/ViewerPreferences` (§12.2, Table 147); `true` sets
853
+ * one, `false` removes it (its default), and other entries (`/Direction`, `/PrintScaling`, …)
854
+ * are kept.
855
+ *
856
+ * When a value needs a later PDF version than the file declares (`UseAttachments` 1.6,
857
+ * `UseOC` and the two-page layouts 1.5, `/DisplayDocTitle` 1.4), the catalog's `/Version` is
858
+ * raised to it. The op is class [`Document`](crate::ModificationClass::Document) and touches no
859
+ * page.
860
+ *
861
+ * On the wire:
862
+ * `{ "op": "setInitialView", "args": { "open": { "page": "p12.0", "zoom": "fitWidth" },
863
+ * "pageMode": "outlines", "pageLayout": null, "preferences": { "displayDocTitle": true } } }`.
864
+ *
865
+ * ```
866
+ * use laminapdf_ops::{OpenAt, OpenZoom, SetInitialView, WindowPreferencesPatch};
867
+ * use laminapdf_model::PageMode;
868
+ *
869
+ * let op = SetInitialView::default()
870
+ * .with_open(Some(OpenAt::new("p3.0".parse()?, OpenZoom::FitWidth)))
871
+ * .with_page_mode(Some(PageMode::Outlines))
872
+ * .with_preferences(WindowPreferencesPatch::default().with_display_doc_title(true));
873
+ * assert_eq!(
874
+ * serde_json::to_string(&op)?,
875
+ * r#"{"open":{"page":"p3.0","zoom":"fitWidth"},"pageMode":"outlines","preferences":{"displayDocTitle":true}}"#
876
+ * );
877
+ * # Ok::<(), Box<dyn std::error::Error>>(())
878
+ * ```
879
+ *
880
+ * Added in 0.3.0.
413
881
  */
414
- export type Op = { op: "setInfo"; args: SetInfo } | { op: "rotatePage"; args: RotatePage };
882
+ export interface SetInitialView {
883
+ /**
884
+ * The page and zoom to open at.
885
+ */
886
+ open?: OpenAt | null;
887
+ /**
888
+ * The panel to show (`/PageMode`).
889
+ */
890
+ pageMode?: "none" | "outlines" | "thumbnails" | "fullScreen" | "optionalContent" | "attachments" | null;
891
+ /**
892
+ * How to lay the pages out (`/PageLayout`).
893
+ */
894
+ pageLayout?: "singlePage" | "oneColumn" | "twoColumnLeft" | "twoColumnRight" | "twoPageLeft" | "twoPageRight" | null;
895
+ /**
896
+ * The window entries of `/ViewerPreferences`.
897
+ */
898
+ preferences?: WindowPreferencesPatch;
899
+ }
415
900
 
416
901
  /**
417
902
  * Changes to the Info dictionary's text entries. For each field, `None` leaves the entry
@@ -420,6 +905,8 @@ export type Op = { op: "setInfo"; args: SetInfo } | { op: "rotatePage"; args: Ro
420
905
  *
421
906
  * On the wire an absent field is left alone and `null` clears: `{ "title": "Report",
422
907
  * "author": null }`.
908
+ *
909
+ * Added in 0.2.0.
423
910
  */
424
911
  export interface InfoPatch {
425
912
  /**
@@ -449,12 +936,216 @@ export interface InfoPatch {
449
936
  }
450
937
 
451
938
  /**
452
- * Edits the Info dictionary: applies `patch` and, when `at` is given, sets `/ModDate` to it.
453
- * The date is part of the op, never read from a clock, so the same op gives the same bytes
454
- * everywhere (ADR 0006 §1).
939
+ * Changes to the document's metadata. For each field, `None` leaves it alone, `Some(None)`
940
+ * removes it and `Some(Some(value))` sets it, in Info and XMP alike.
941
+ *
942
+ * On the wire an absent field is left alone and `null` removes: `{ "title": "Report",
943
+ * "authors": ["Ada Lovelace", "Charles Babbage"], "keywords": null }`; dates are PDF date
944
+ * strings (`"D:20261110093000+01'00'"`).
945
+ *
946
+ * ```
947
+ * use laminapdf_ops::MetadataPatch;
948
+ *
949
+ * let patch = MetadataPatch::new().title(Some("Quarterly figures")).authors(&["Ada Lovelace", "Charles Babbage"]);
950
+ * assert_eq!(patch.authors, Some(Some(vec!["Ada Lovelace".to_owned(), "Charles Babbage".to_owned()])));
951
+ * assert_eq!(serde_json::to_string(&patch)?, r#"{"title":"Quarterly figures","authors":["Ada Lovelace","Charles Babbage"]}"#);
952
+ * # Ok::<(), serde_json::Error>(())
953
+ * ```
954
+ *
955
+ * Added in 0.2.0.
956
+ */
957
+ export interface MetadataPatch {
958
+ /**
959
+ * `/Title`, `dc:title`.
960
+ */
961
+ title?: string | null;
962
+ /**
963
+ * `/Author` (joined with `; `), `dc:creator` (in order). An empty list removes them.
964
+ */
965
+ authors?: string[] | null;
966
+ /**
967
+ * `/Subject`, `dc:description`.
968
+ */
969
+ subject?: string | null;
970
+ /**
971
+ * `/Keywords`, `pdf:Keywords`.
972
+ */
973
+ keywords?: string | null;
974
+ /**
975
+ * `/Creator`, `xmp:CreatorTool`: the application the content came from.
976
+ */
977
+ creator?: string | null;
978
+ /**
979
+ * `/Producer`, `pdf:Producer`: the application that wrote the PDF.
980
+ */
981
+ producer?: string | null;
982
+ /**
983
+ * `/CreationDate`, `xmp:CreateDate`.
984
+ */
985
+ created?: string | null;
986
+ /**
987
+ * `/ModDate`, `xmp:ModifyDate`.
988
+ */
989
+ modified?: string | null;
990
+ }
991
+
992
+ /**
993
+ * Copies `pages` (each once, in the order given) to `at`. A copy shares its source's content
994
+ * streams and resources and shows what it shows, inherited attributes included (ISO 32000-2
995
+ * §7.7.3.4). Its annotations are new objects with a new `/NM`; a form field's widget becomes
996
+ * a new field named `<partial>#<n>` with its own value, and a signature's widget is not copied
997
+ * (both in [`Applied::fields`](crate::Applied::fields)). In a tagged document the copy gets
998
+ * its own `/StructParents` key and clones of the elements whose content lies only on its
999
+ * source; content of elements that span pages is left untagged and the copy is listed in
1000
+ * [`Applied::tags_incomplete`](crate::Applied::tags_incomplete). Page labels continue the range
1001
+ * each copy lands in.
1002
+ *
1003
+ * On the wire: `{ "op": "duplicatePages", "args": { "pages": ["p7.0"], "at": { "after": "p7.0" } } }`.
1004
+ *
1005
+ * Added in 0.3.0.
1006
+ */
1007
+ export interface DuplicatePages {
1008
+ /**
1009
+ * The pages to copy.
1010
+ */
1011
+ pages: string[];
1012
+ /**
1013
+ * Where the copies go.
1014
+ */
1015
+ at: "start" | "end" | { before: string } | { after: string };
1016
+ }
1017
+
1018
+ /**
1019
+ * Copies pages of a source document into this one at `at`, in the order given (each once).
1020
+ * The copies are new objects with new IDs, sharing nothing with the source. Their
1021
+ * annotations point at them and get a new `/NM`; a link to a page that didn't come along is
1022
+ * removed ([`Applied::links_removed`](crate::Applied::links_removed)), and the named
1023
+ * destinations the others use come along, renamed `<name>#<n>` on a clash. Form fields join
1024
+ * the form under their own names, or per [`Carry::fields`] when the name is taken
1025
+ * ([`Applied::fields`](crate::Applied::fields)); signature fields are left off. The copies
1026
+ * lose their tags ([`Applied::tags_dropped`](crate::Applied::tags_dropped)), page labels
1027
+ * continue the range each copy lands in, and the document's version rises to the source's
1028
+ * when that is newer.
1029
+ *
1030
+ * On the wire: `{ "op": "insertPagesFrom", "args": { "source": "<64 hex digits>", "pages":
1031
+ * ["p3.0"], "at": "end" } }`, with `carry` optional.
1032
+ *
1033
+ * Added in 0.3.0.
1034
+ */
1035
+ export interface InsertPagesFrom {
1036
+ /**
1037
+ * The source document.
1038
+ */
1039
+ source: string;
1040
+ /**
1041
+ * The source's pages to copy, by their IDs in the source.
1042
+ */
1043
+ pages: string[];
1044
+ /**
1045
+ * Where the copies go.
1046
+ */
1047
+ at: "start" | "end" | { before: string } | { after: string };
1048
+ /**
1049
+ * What comes along with the pages.
1050
+ */
1051
+ carry?: Carry;
1052
+ }
1053
+
1054
+ /**
1055
+ * Deletes `pages` (each once; unknown pages are an error). Outline items, links and `GoTo`
1056
+ * actions on surviving pages, named destinations and `/OpenAction` that named a deleted page
1057
+ * follow `references` ([`ReferencePolicy`]); structure elements whose content was all on
1058
+ * deleted pages are removed with their `/ParentTree` entries, and the widgets on deleted pages
1059
+ * leave the form (a field left with none leaves it too). The page objects stay in the file's
1060
+ * earlier revisions. Deleting every page is [`Error::NoPagesLeft`].
1061
+ *
1062
+ * On the wire: `{ "op": "deletePages", "args": { "pages": ["p7.0"], "references": "retarget" } }`.
1063
+ *
1064
+ * Added in 0.3.0.
1065
+ */
1066
+ export interface DeletePages {
1067
+ /**
1068
+ * The pages.
1069
+ */
1070
+ pages: string[];
1071
+ /**
1072
+ * What happens to destinations that name them; `retarget` when left out.
1073
+ */
1074
+ references?: ReferencePolicy;
1075
+ }
1076
+
1077
+ /**
1078
+ * Deletes a bookmark, and its children with it or moved up into its place.
1079
+ *
1080
+ * On the wire: `{ "op": "deleteOutlineItem", "args": { "item": "o12.0", "children":
1081
+ * "promote" } }`.
1082
+ *
1083
+ * Added in 0.3.0.
1084
+ */
1085
+ export interface DeleteOutlineItem {
1086
+ /**
1087
+ * The item.
1088
+ */
1089
+ item: string;
1090
+ /**
1091
+ * What happens to its children.
1092
+ */
1093
+ children: ChildItems;
1094
+ }
1095
+
1096
+ /**
1097
+ * Deletes a named destination, from both stores when both hold it. Its uses in this file are left as they are and reported
1098
+ * ([`Applied::destination_uses`](crate::Applied::destination_uses)): a bookmark or link that
1099
+ * names it no longer goes anywhere.
1100
+ *
1101
+ * On the wire: `{ "op": "deleteNamedDestination", "args": { "name": "draft-notes" } }`.
1102
+ *
1103
+ * Added in 0.3.0.
1104
+ */
1105
+ export interface DeleteNamedDestination {
1106
+ /**
1107
+ * The name.
1108
+ */
1109
+ name: string;
1110
+ }
1111
+
1112
+ /**
1113
+ * Deletes an annotation with what belongs to it: its Popup, every reply whose `/IRT` chain
1114
+ * reaches it, and, for a member of a group (`/RT /Group`, §12.5.6.2), the whole group, which
1115
+ * is one unit. Chains are followed through cycles once. In a tagged document, the structure
1116
+ * element's object reference to each deleted annotation is removed, and so is an element left
1117
+ * with nothing in it. Each deleted object is freed.
1118
+ *
1119
+ * A `Locked` annotation is refused (`annotation-locked`), and so are widgets and direct
1120
+ * dictionaries (`annotation-not-editable`). Deleting a Popup alone removes the `/Popup` entry
1121
+ * that names it.
1122
+ *
1123
+ * On the wire: `{ "op": "deleteAnnot", "args": { "id": "a12.0" } }`.
1124
+ *
1125
+ * Added in 0.3.0.
1126
+ */
1127
+ export interface DeleteAnnot {
1128
+ /**
1129
+ * The annotation.
1130
+ */
1131
+ id: string;
1132
+ }
1133
+
1134
+ /**
1135
+ * Edits the Info dictionary: applies `patch` and, when `at` is given, sets `/ModDate` to it.
1136
+ *
1137
+ * **Deprecated:** use [`SetMetadata`](crate::SetMetadata), which writes authors as a list and
1138
+ * the dates, and edits files whose metadata is in XMP alone. `SetInfo` stays, with its v1 wire
1139
+ * form (`setInfo`) and meaning, so op logs already written still apply (ADR 0006 §6). It now
1140
+ * goes through the same writer, so a document's XMP packet, when it has one, changes with it.
1141
+ * It adds a packet only to a PDF 2.0 file, where the fields other than the dates belong in XMP.
1142
+ * The date is part of the op, never read from a clock, so the same op gives the same bytes
1143
+ * everywhere (ADR 0006 §1).
455
1144
  *
456
1145
  * An Info dictionary written directly in the trailer, or missing, becomes a new indirect
457
1146
  * object that the trailer's `/Info` points to (the first time the op changes something).
1147
+ *
1148
+ * Added in 0.2.0.
458
1149
  */
459
1150
  export interface SetInfo {
460
1151
  /**
@@ -467,6 +1158,84 @@ export interface SetInfo {
467
1158
  at?: string;
468
1159
  }
469
1160
 
1161
+ /**
1162
+ * Edits the document's metadata: applies `patch` to the Info dictionary and the XMP packet
1163
+ * together and, when `at` is given, records it as the modification date (`/ModDate`,
1164
+ * `xmp:ModifyDate`) and as `xmp:MetadataDate`, unless the patch sets the modification date
1165
+ * itself. The date is part of the op, never read from a clock (ADR 0006 §1).
1166
+ *
1167
+ * ```
1168
+ * use laminapdf_ops::{MetadataPatch, Op, SetMetadata};
1169
+ *
1170
+ * let op = Op::from(SetMetadata::new(MetadataPatch::new().title(Some("Minutes")), Some("D:20261110093000Z".parse()?)));
1171
+ * assert_eq!(
1172
+ * serde_json::to_string(&op)?,
1173
+ * r#"{"op":"setMetadata","args":{"patch":{"title":"Minutes"},"at":"D:20261110093000Z"}}"#
1174
+ * );
1175
+ * # Ok::<(), Box<dyn std::error::Error>>(())
1176
+ * ```
1177
+ *
1178
+ * Added in 0.2.0.
1179
+ */
1180
+ export interface SetMetadata {
1181
+ /**
1182
+ * The fields to set or remove.
1183
+ */
1184
+ patch?: MetadataPatch;
1185
+ /**
1186
+ * The modification date the edit writes.
1187
+ */
1188
+ at?: string;
1189
+ /**
1190
+ * Replace an XMP packet that can't be read with a new one, losing whatever it held.
1191
+ * Without it, such a packet makes the op fail with `malformed-xmp`, so nothing is lost
1192
+ * without the user saying so.
1193
+ */
1194
+ replaceMalformed?: boolean;
1195
+ }
1196
+
1197
+ /**
1198
+ * How [`RotatePages`] reads its angle.
1199
+ *
1200
+ * Added in 0.3.0.
1201
+ */
1202
+ export type RotateMode = "set" | "turn";
1203
+
1204
+ /**
1205
+ * How [`images_to_pdf`] sizes its pages.
1206
+ */
1207
+ export interface ImagesOptionsInit {
1208
+ /**
1209
+ * Each page this size, `[width, height]` in points, turned the image's way, the image fitted
1210
+ * inside the margins and centred. Without it, each page is its image's size at the image's
1211
+ * resolution.
1212
+ */
1213
+ fit?: [number, number];
1214
+ /**
1215
+ * The space around each image, in points (0 by default).
1216
+ */
1217
+ margin?: number;
1218
+ /**
1219
+ * The resolution of an image whose file gives none, in dots per inch (72 by default).
1220
+ */
1221
+ defaultDpi?: number;
1222
+ /**
1223
+ * The new document's version, file ID, producer, creation date and compression.
1224
+ */
1225
+ build?: BuildOptionsInit;
1226
+ }
1227
+
1228
+ /**
1229
+ * How `flow` reads its document.
1230
+ */
1231
+ export interface FlowOptionsInit {
1232
+ /**
1233
+ * The values a template's `$data`, `$each` and `$item` placeholders read; without it, the
1234
+ * document is read as it is.
1235
+ */
1236
+ data?: unknown;
1237
+ }
1238
+
470
1239
  /**
471
1240
  * How `markdown` lays a document out.
472
1241
  */
@@ -490,6 +1259,38 @@ export interface MarkdownOptionsInit {
490
1259
  */
491
1260
  export type FitInit = { type: "page" } | { type: "width"; top?: number } | { type: "height"; left?: number } | { type: "xyz"; left?: number; top?: number; zoom?: number } | { type: "rect"; x: number; y: number; width: number; height: number } | { type: "bounds" };
492
1261
 
1262
+ /**
1263
+ * How a destination shows its page (§12.3.2.2, Table 149), in the page's user space. A `None`
1264
+ * coordinate keeps the viewer's current one (`null` in the file).
1265
+ *
1266
+ * Every number must be finite: the ops refuse any other with `view-not-finite`.
1267
+ *
1268
+ * Added in 0.3.0.
1269
+ */
1270
+ export type DestinationView = { kind: "xyz"; left: number | undefined; top: number | undefined; zoom: number | undefined } | { kind: "fit" } | { kind: "fitH"; top: number | undefined } | { kind: "fitV"; left: number | undefined } | { kind: "fitR"; left: number; bottom: number; right: number; top: number } | { kind: "fitB" } | { kind: "fitBH"; top: number | undefined } | { kind: "fitBV"; left: number | undefined };
1271
+
1272
+ /**
1273
+ * How a document asks to be shown when it opens.
1274
+ */
1275
+ export interface InitialViewJs {
1276
+ /**
1277
+ * Where it opens.
1278
+ */
1279
+ open: OpenTargetJs;
1280
+ /**
1281
+ * The panel to show; left out when the file leaves it to the reader.
1282
+ */
1283
+ pageMode?: "none" | "outlines" | "thumbnails" | "fullScreen" | "optionalContent" | "attachments";
1284
+ /**
1285
+ * How to lay the pages out; left out when the file leaves it to the reader.
1286
+ */
1287
+ pageLayout?: "singlePage" | "oneColumn" | "twoColumnLeft" | "twoColumnRight" | "twoPageLeft" | "twoPageRight";
1288
+ /**
1289
+ * The window's viewer preferences.
1290
+ */
1291
+ preferences: WindowPreferencesJs;
1292
+ }
1293
+
493
1294
  /**
494
1295
  * How a file is encrypted, and what its author permits.
495
1296
  */
@@ -516,6 +1317,22 @@ export interface EncryptionJs {
516
1317
  permissions?: PermissionsJs;
517
1318
  }
518
1319
 
1320
+ /**
1321
+ * How a merge brings in what the sources hold besides their pages.
1322
+ *
1323
+ * Added in 0.3.0.
1324
+ */
1325
+ export interface MergeOptions {
1326
+ /**
1327
+ * What becomes of the sources' bookmarks; `perFile` when left out.
1328
+ */
1329
+ outline?: OutlineMerge;
1330
+ /**
1331
+ * What happens to a form field whose name is already used; `rename` when left out.
1332
+ */
1333
+ fields?: FieldClash;
1334
+ }
1335
+
519
1336
  /**
520
1337
  * How a run of text is drawn.
521
1338
  */
@@ -546,6 +1363,65 @@ export interface TextOptionsInit {
546
1363
  direction?: DirectionInit;
547
1364
  }
548
1365
 
1366
+ /**
1367
+ * How a save would go (`laminapdf::PlannedSave`).
1368
+ */
1369
+ export interface PlannedSaveJs {
1370
+ /**
1371
+ * The mode the save resolves to; absent when it would be refused.
1372
+ */
1373
+ mode?: SaveModeJs;
1374
+ /**
1375
+ * The code the save would be refused with.
1376
+ */
1377
+ refusal?: string;
1378
+ /**
1379
+ * `free`, `appendOnly`, `requiresRewrite` or `conflict`.
1380
+ */
1381
+ constraint: string;
1382
+ /**
1383
+ * Every signature, in the order found.
1384
+ */
1385
+ signatures: SignatureJs[];
1386
+ /**
1387
+ * The certification's `/P` (1, 2 or 3), when the document is certified.
1388
+ */
1389
+ docMdp?: number;
1390
+ /**
1391
+ * Why only a full rewrite is safe: `repairedBase`, `encryptedBase`, `noBase`,
1392
+ * `opRequiresRewrite`.
1393
+ */
1394
+ rewriteReasons: string[];
1395
+ /**
1396
+ * The pending changes a signature's restriction forbids.
1397
+ */
1398
+ violations: ViolationJs[];
1399
+ /**
1400
+ * The signatures the save would invalidate (only with `invalidateSignatures`).
1401
+ */
1402
+ wouldInvalidate: SignatureJs[];
1403
+ /**
1404
+ * Whether the save writes an encrypted document as plaintext.
1405
+ */
1406
+ removesEncryption: boolean;
1407
+ /**
1408
+ * What the save does with the save-time metadata: `none`, `stamp` or `skipped`.
1409
+ */
1410
+ metadata: string;
1411
+ /**
1412
+ * Whether an edit to save rewrote the XMP packet whole.
1413
+ */
1414
+ packetRewritten: boolean;
1415
+ /**
1416
+ * The PDF/A and PDF/UA claims the edited metadata breaks (warnings that never block).
1417
+ */
1418
+ conformanceWarnings: Diagnostic[];
1419
+ /**
1420
+ * The document has no changes.
1421
+ */
1422
+ unchanged: boolean;
1423
+ }
1424
+
549
1425
  /**
550
1426
  * How a target shows its page, in page space; an unset coordinate is left out.
551
1427
  */
@@ -556,77 +1432,300 @@ export type TargetViewJs = { kind: "at"; x?: number; y?: number; zoom?: number }
556
1432
  */
557
1433
  export interface TextLayoutJs {
558
1434
  /**
559
- * The lines drawn.
1435
+ * The lines drawn.
1436
+ */
1437
+ lines: LineBoxJs[];
1438
+ /**
1439
+ * Where the text that didn't fit starts (UTF-16 offset), if any; `0` when no line fitted.
1440
+ */
1441
+ overflow?: number;
1442
+ /**
1443
+ * Where the next element can start: the bottom of the last drawn line that draws
1444
+ * something, before the surface's transform. Left out when no line does (nothing, only
1445
+ * white space and control characters, or a box too short).
1446
+ */
1447
+ bottom?: number;
1448
+ }
1449
+
1450
+ /**
1451
+ * How a viewer lays pages out.
1452
+ */
1453
+ export type PageLayoutInit = "singlePage" | "oneColumn" | "twoColumnLeft" | "twoColumnRight" | "twoPageLeft" | "twoPageRight";
1454
+
1455
+ /**
1456
+ * How an attached file relates to the document (`/AFRelationship`).
1457
+ */
1458
+ export type AfRelationshipInit = "source" | "data" | "alternative" | "supplement" | "unspecified";
1459
+
1460
+ /**
1461
+ * How an undo or redo went (`laminapdf::UndoOutcome`).
1462
+ */
1463
+ export type UndoOutcomeJs = "applied" | "partial" | "skipped";
1464
+
1465
+ /**
1466
+ * How the Markdown is cut into chunks.
1467
+ */
1468
+ export interface ChunkInit {
1469
+ /**
1470
+ * A chunk's budget in approximate tokens (characters / 4); 512 by default.
1471
+ */
1472
+ maxTokens?: number;
1473
+ /**
1474
+ * Approximate tokens of whole blocks repeated from the chunk before; 0 by default.
1475
+ */
1476
+ overlap?: number;
1477
+ /**
1478
+ * Where chunks may start; `"headings"` by default.
1479
+ */
1480
+ splitOn?: SplitOnName;
1481
+ }
1482
+
1483
+ /**
1484
+ * How viewers present the document when it opens.
1485
+ */
1486
+ export interface ViewerPreferencesInit {
1487
+ /**
1488
+ * Show the title, not the file name.
1489
+ */
1490
+ displayDocTitle?: boolean;
1491
+ /**
1492
+ * The panel shown.
1493
+ */
1494
+ pageMode?: PageModeInit;
1495
+ /**
1496
+ * The page layout.
1497
+ */
1498
+ pageLayout?: PageLayoutInit;
1499
+ }
1500
+
1501
+ /**
1502
+ * Inserts `count` blank pages of `size` at `at`, each showing at `rotate`. Each new page
1503
+ * gets a new object and [`PageId`] (ADR 0005 §5), an empty `/Resources` and no content; in
1504
+ * a labelled document they continue the label range they land in. A count outside 1 to
1505
+ * 10,000, or a side that isn't above 0 and at most 14,400 points, is
1506
+ * [`Error::InvalidOp`](crate::Error::InvalidOp).
1507
+ *
1508
+ * On the wire: `{ "op": "insertBlankPages", "args": { "at": { "after": "p3.0" }, "count": 2,
1509
+ * "size": { "width": 612, "height": 792 }, "rotate": 0 } }`.
1510
+ *
1511
+ * Added in 0.3.0.
1512
+ */
1513
+ export interface InsertBlankPages {
1514
+ /**
1515
+ * Where the pages go.
1516
+ */
1517
+ at: "start" | "end" | { before: string } | { after: string };
1518
+ /**
1519
+ * How many pages, at least 1.
1520
+ */
1521
+ count: number;
1522
+ /**
1523
+ * Their `/MediaBox` size, in points: `{ "width": 612, "height": 792 }`.
1524
+ */
1525
+ size: { width: number; height: number };
1526
+ /**
1527
+ * Their rotation in degrees clockwise: 0, 90, 180 or 270.
1528
+ */
1529
+ rotate: 0 | 90 | 180 | 270;
1530
+ }
1531
+
1532
+ /**
1533
+ * Merges source documents into this one at `at`, one after another, as one edit. Each
1534
+ * source's pages come in as [`InsertPagesFrom`](crate::InsertPagesFrom) brings them (their
1535
+ * annotations, links and the named destinations those use, form fields under the clash rule
1536
+ * of `options.fields`, signature fields left off, tags dropped), and with them what belongs to
1537
+ * the whole source:
1538
+ *
1539
+ * - its bookmarks, per `options.outline`, going to the copies of their pages; a bookmark whose
1540
+ * page didn't come along is left out unless one of its children came
1541
+ * ([`Applied::bookmarks_dropped`](crate::Applied::bookmarks_dropped));
1542
+ * - its layers (optional content groups the copied pages use), added to this document's list
1543
+ * in the source's order and visible or hidden as the source showed them;
1544
+ * - its page labels: each copy keeps the label it had in its source, and this document's
1545
+ * pages keep theirs (a document without labels numbers its pages from 1);
1546
+ * - its form's default appearance and `/NeedAppearances`, and its PDF version when newer.
1547
+ *
1548
+ * Named destinations that clash are renamed `<name>#<n>`
1549
+ * ([`Applied::renamed_destinations`](crate::Applied::renamed_destinations)).
1550
+ *
1551
+ * On the wire: `{ "op": "mergeDocuments", "args": { "sources": [{ "source": "<64 hex
1552
+ * digits>" }], "at": "end" } }`, with each source's `pages` and `title`, and `options`,
1553
+ * optional.
1554
+ *
1555
+ * Added in 0.3.0.
1556
+ */
1557
+ export interface MergeDocuments {
1558
+ /**
1559
+ * The documents to bring in, in order.
1560
+ */
1561
+ sources: MergeSource[];
1562
+ /**
1563
+ * Where their pages go.
1564
+ */
1565
+ at: "start" | "end" | { before: string } | { after: string };
1566
+ /**
1567
+ * What comes along besides the pages.
1568
+ */
1569
+ options?: MergeOptions;
1570
+ }
1571
+
1572
+ /**
1573
+ * Moves `pages` to `to`. They keep their order among themselves (the order given, each page
1574
+ * once) and their IDs; an anchor that is itself moved is replaced by the nearest page that
1575
+ * stays.
1576
+ *
1577
+ * On the wire: `{ "op": "movePages", "args": { "pages": ["p7.0", "p8.0"], "to": "start" } }`.
1578
+ *
1579
+ * Added in 0.3.0.
1580
+ */
1581
+ export interface MovePages {
1582
+ /**
1583
+ * The pages, in the order they take at `to`.
1584
+ */
1585
+ pages: string[];
1586
+ /**
1587
+ * Where they go.
1588
+ */
1589
+ to: "start" | "end" | { before: string } | { after: string };
1590
+ }
1591
+
1592
+ /**
1593
+ * Moves a bookmark, with its children, under `parent` (`null`: the top level) at `at`. The
1594
+ * item keeps its ID.
1595
+ *
1596
+ * On the wire: `{ "op": "moveOutlineItem", "args": { "item": "o12.0", "parent": "o9.0", "at":
1597
+ * { "after": "o10.0" } } }`.
1598
+ *
1599
+ * Added in 0.3.0.
1600
+ */
1601
+ export interface MoveOutlineItem {
1602
+ /**
1603
+ * The item.
1604
+ */
1605
+ item: string;
1606
+ /**
1607
+ * The new parent; `None` for the top level.
1608
+ */
1609
+ parent?: string | null;
1610
+ /**
1611
+ * Where among the new parent's children.
1612
+ */
1613
+ at: "first" | "last" | { before: string } | { after: string };
1614
+ }
1615
+
1616
+ /**
1617
+ * Object numbering in a full rewrite.
1618
+ */
1619
+ export type RenumberJs = "keep" | "compact";
1620
+
1621
+ /**
1622
+ * One annotation on a page, in page space.
1623
+ */
1624
+ export interface PageAnnotationJs {
1625
+ /**
1626
+ * Its ID (`a12.0`), as `updateAnnot` and `deleteAnnot` take it.
1627
+ */
1628
+ id: string;
1629
+ /**
1630
+ * Its position in the page's `/Annots`.
1631
+ */
1632
+ index: number;
1633
+ /**
1634
+ * Its subtype as written (`Highlight`, `Text`, …).
1635
+ */
1636
+ subtype: string;
1637
+ /**
1638
+ * Its rectangle: `[x0, y0, x1, y1]`, top-left and bottom-right; left out when it has none.
1639
+ */
1640
+ rect?: [number, number, number, number];
1641
+ /**
1642
+ * `/Contents` (document text).
1643
+ */
1644
+ contents?: string;
1645
+ /**
1646
+ * `/NM` (document text), only a hint.
1647
+ */
1648
+ name?: string;
1649
+ /**
1650
+ * `/T`, the author.
1651
+ */
1652
+ author?: string;
1653
+ /**
1654
+ * `/Subj`.
1655
+ */
1656
+ subject?: string;
1657
+ /**
1658
+ * `/CreationDate` as stored.
1659
+ */
1660
+ created?: string;
1661
+ /**
1662
+ * `/M` as stored.
1663
+ */
1664
+ modified?: string;
1665
+ /**
1666
+ * `/F`, the flags.
1667
+ */
1668
+ flags: number;
1669
+ /**
1670
+ * `/C`: no components (transparent), one (gray), three (RGB) or four (CMYK).
1671
+ */
1672
+ color: number[];
1673
+ /**
1674
+ * `/CA`, the opacity.
1675
+ */
1676
+ opacity?: number;
1677
+ /**
1678
+ * The ID of the annotation this one replies to or is grouped with.
560
1679
  */
561
- lines: LineBoxJs[];
1680
+ inReplyTo?: string;
562
1681
  /**
563
- * Where the text that didn't fit starts (UTF-16 offset), if any; `0` when no line fitted.
1682
+ * Whether `inReplyTo` is a group rather than a reply.
564
1683
  */
565
- overflow?: number;
1684
+ grouped: boolean;
566
1685
  /**
567
- * Where the next element can start: the bottom of the last drawn line that draws
568
- * something, before the surface's transform. Left out when no line does (nothing, only
569
- * white space and control characters, or a box too short).
1686
+ * The ID of its Popup.
570
1687
  */
571
- bottom?: number;
572
- }
573
-
574
- /**
575
- * How a viewer lays pages out.
576
- */
577
- export type PageLayoutInit = "singlePage" | "oneColumn" | "twoColumnLeft" | "twoColumnRight" | "twoPageLeft" | "twoPageRight";
578
-
579
- /**
580
- * How an attached file relates to the document (`/AFRelationship`).
581
- */
582
- export type AfRelationshipInit = "source" | "data" | "alternative" | "supplement" | "unspecified";
583
-
584
- /**
585
- * How an undo or redo went (`laminapdf::UndoOutcome`).
586
- */
587
- export type UndoOutcomeJs = "applied" | "partial" | "skipped";
588
-
589
- /**
590
- * How the Markdown is cut into chunks.
591
- */
592
- export interface ChunkInit {
1688
+ popup?: string;
593
1689
  /**
594
- * A chunk's budget in approximate tokens (characters / 4); 512 by default.
1690
+ * For a Popup, the ID of the annotation it belongs to.
595
1691
  */
596
- maxTokens?: number;
1692
+ parent?: string;
597
1693
  /**
598
- * Approximate tokens of whole blocks repeated from the chunk before; 0 by default.
1694
+ * Whether it has a normal appearance stream.
599
1695
  */
600
- overlap?: number;
1696
+ hasAppearance: boolean;
601
1697
  /**
602
- * Where chunks may start; `"headings"` by default.
1698
+ * Whether it has rich-text contents.
603
1699
  */
604
- splitOn?: SplitOnName;
1700
+ hasRichText: boolean;
1701
+ /**
1702
+ * The subtype's own geometry, as flat `[x, y, …]` lists in page space.
1703
+ */
1704
+ geometry: GeometryJs;
605
1705
  }
606
1706
 
607
1707
  /**
608
- * How viewers present the document when it opens.
1708
+ * One document a merge brings in.
1709
+ *
1710
+ * Added in 0.3.0.
609
1711
  */
610
- export interface ViewerPreferencesInit {
1712
+ export interface MergeSource {
611
1713
  /**
612
- * Show the title, not the file name.
1714
+ * The source document, added with [`Document::add_source`](crate::Document::add_source).
613
1715
  */
614
- displayDocTitle?: boolean;
1716
+ source: string;
615
1717
  /**
616
- * The panel shown.
1718
+ * The source's pages to bring in, by their IDs in the source, in order; all of them when
1719
+ * left out.
617
1720
  */
618
- pageMode?: PageModeInit;
1721
+ pages?: string[];
619
1722
  /**
620
- * The page layout.
1723
+ * The name of the bookmark [`OutlineMerge::PerFile`] gives the source's bookmarks (a file
1724
+ * name, say); the source's own title when left out.
621
1725
  */
622
- pageLayout?: PageLayoutInit;
1726
+ title?: string;
623
1727
  }
624
1728
 
625
- /**
626
- * Object numbering in a full rewrite.
627
- */
628
- export type RenumberJs = "keep" | "compact";
629
-
630
1729
  /**
631
1730
  * One drawn line of a text box. Offsets are UTF-16 code units into the text (JS
632
1731
  * string indices).
@@ -680,6 +1779,14 @@ export interface StructureNodeJs {
680
1779
  kids: StructureKidJs[];
681
1780
  }
682
1781
 
1782
+ /**
1783
+ * One entry of a language alternative, under the name TypeScript gives it.
1784
+ */
1785
+ export interface XmpLangText {
1786
+ lang: string;
1787
+ text: string;
1788
+ }
1789
+
683
1790
  /**
684
1791
  * One font the document uses.
685
1792
  */
@@ -706,6 +1813,20 @@ export interface FontJs {
706
1813
  encoding?: EncodingJs;
707
1814
  }
708
1815
 
1816
+ /**
1817
+ * One named destination and where it goes.
1818
+ */
1819
+ export interface NamedDestinationJs {
1820
+ /**
1821
+ * The name.
1822
+ */
1823
+ name: string;
1824
+ /**
1825
+ * Where it goes, when it names a page of this document.
1826
+ */
1827
+ target?: TargetJs;
1828
+ }
1829
+
709
1830
  /**
710
1831
  * One outline item and its children.
711
1832
  */
@@ -744,6 +1865,10 @@ export interface OutlineEntryInit {
744
1865
  * One outline item.
745
1866
  */
746
1867
  export interface OutlineNodeJs {
1868
+ /**
1869
+ * Its ID (`o12.0`), which the outline ops take.
1870
+ */
1871
+ id: string;
747
1872
  /**
748
1873
  * Its title (document text).
749
1874
  */
@@ -756,6 +1881,30 @@ export interface OutlineNodeJs {
756
1881
  * Where it goes, when its destination names a page of this document.
757
1882
  */
758
1883
  target?: TargetJs;
1884
+ /**
1885
+ * The named destination it goes to, when it names one.
1886
+ */
1887
+ destinationName?: string;
1888
+ /**
1889
+ * The web address it opens, when it has one.
1890
+ */
1891
+ uri?: string;
1892
+ /**
1893
+ * Its action's type when that is neither `GoTo` nor `URI` (`JavaScript`, `Launch`, …).
1894
+ */
1895
+ otherAction?: string;
1896
+ /**
1897
+ * Its colour as `"#rrggbb"`, when it isn't the default black.
1898
+ */
1899
+ color?: string;
1900
+ /**
1901
+ * Shown in bold.
1902
+ */
1903
+ bold: boolean;
1904
+ /**
1905
+ * Shown in italic.
1906
+ */
1907
+ italic: boolean;
759
1908
  /**
760
1909
  * Its children, in order.
761
1910
  */
@@ -814,6 +1963,73 @@ export interface PageLabelInit {
814
1963
  first?: number;
815
1964
  }
816
1965
 
1966
+ /**
1967
+ * One part of an article thread.
1968
+ */
1969
+ export interface ThreadPartJs {
1970
+ /**
1971
+ * The page's 0-based index; left out when the part names a page the document lacks.
1972
+ */
1973
+ page?: number;
1974
+ /**
1975
+ * Its rectangle, `[x0, y0, x1, y1]` in page space; left out when unreadable.
1976
+ */
1977
+ rect?: [number, number, number, number];
1978
+ }
1979
+
1980
+ /**
1981
+ * One range of [`SetPageLabels`]: the labels from `page` up to the next range's page.
1982
+ *
1983
+ * Added in 0.3.0.
1984
+ */
1985
+ export interface PageLabelRange {
1986
+ /**
1987
+ * The range's first page.
1988
+ */
1989
+ page: string;
1990
+ /**
1991
+ * The numbering style; without one, each label is the prefix alone. On the wire:
1992
+ * `decimal`, `upperRoman`, `lowerRoman`, `upperLetters` or `lowerLetters`.
1993
+ */
1994
+ style?: "decimal" | "upperRoman" | "lowerRoman" | "upperLetters" | "lowerLetters";
1995
+ /**
1996
+ * Text before each number (`A-` in `A-1`).
1997
+ */
1998
+ prefix?: string;
1999
+ /**
2000
+ * The number of the range's first page, 1 or more (a `u32`, as the builder's page labels
2001
+ * take).
2002
+ */
2003
+ first?: number;
2004
+ }
2005
+
2006
+ /**
2007
+ * One reference to a deleted page and what the deletion did to it.
2008
+ */
2009
+ export interface ReferenceEditJs {
2010
+ /**
2011
+ * The deleted page it named.
2012
+ */
2013
+ page: string;
2014
+ /**
2015
+ * `outlineItem`, `link`, `namedDestination`, `openAction`, `structureElement`,
2016
+ * `structureKid` or `widget`.
2017
+ */
2018
+ kind: "outlineItem" | "link" | "namedDestination" | "openAction" | "structureElement" | "structureKid" | "widget";
2019
+ /**
2020
+ * The named destination's name, for a `namedDestination`.
2021
+ */
2022
+ name?: string;
2023
+ /**
2024
+ * `retargeted` or `removed`.
2025
+ */
2026
+ outcome: "retargeted" | "removed";
2027
+ /**
2028
+ * The surviving page it now names, when retargeted.
2029
+ */
2030
+ to?: string;
2031
+ }
2032
+
817
2033
  /**
818
2034
  * One text run (`laminapdf::extract::PageTextRun`): glyphs of one font, size, direction and marked
819
2035
  * content on one baseline, in logical order.
@@ -1022,6 +2238,17 @@ export interface SaveOptionsInit {
1022
2238
  * The cross-reference form.
1023
2239
  */
1024
2240
  xref?: XrefJs;
2241
+ /**
2242
+ * When the save happens, as the app's clock reads it: a PDF date (`D:20261110093000Z`)
2243
+ * or an ISO 8601 date-time. A save that writes changes stamps it as the modification and
2244
+ * metadata dates and gives the XMP packet a new instance ID.
2245
+ */
2246
+ metadataDate?: string;
2247
+ /**
2248
+ * The XMP instance ID the save writes, a UUID (`uuid:` optional); without it, one is
2249
+ * derived from the content.
2250
+ */
2251
+ instanceId?: string;
1025
2252
  }
1026
2253
 
1027
2254
  /**
@@ -1029,6 +2256,215 @@ export interface SaveOptionsInit {
1029
2256
  */
1030
2257
  export type DirectionInit = "ltr" | "rtl";
1031
2258
 
2259
+ /**
2260
+ * Removes an XMP property, every copy of it in the packet; a property the Info dictionary
2261
+ * mirrors is removed from both. The value stays in the file's earlier revisions until a full
2262
+ * rewrite ([`Applied::still_in_earlier_revisions`](crate::Applied::still_in_earlier_revisions)).
2263
+ *
2264
+ * ```
2265
+ * use laminapdf_ops::{Op, RemoveXmpProperty};
2266
+ *
2267
+ * let op = Op::from(RemoveXmpProperty::new("http://example.com/ns/", "batch"));
2268
+ * assert_eq!(
2269
+ * serde_json::to_string(&op)?,
2270
+ * r#"{"op":"removeXmpProperty","args":{"namespace":"http://example.com/ns/","name":"batch"}}"#
2271
+ * );
2272
+ * # Ok::<(), serde_json::Error>(())
2273
+ * ```
2274
+ *
2275
+ * Added in 0.3.0.
2276
+ */
2277
+ export interface RemoveXmpProperty {
2278
+ /**
2279
+ * The property's namespace URI.
2280
+ */
2281
+ namespace: string;
2282
+ /**
2283
+ * The property's local name.
2284
+ */
2285
+ name: string;
2286
+ /**
2287
+ * As [`SetMetadata::replace_malformed`](crate::SetMetadata::replace_malformed).
2288
+ */
2289
+ replaceMalformed?: boolean;
2290
+ }
2291
+
2292
+ /**
2293
+ * Removes metadata fields from the Info dictionary and the XMP packet; the packet's other
2294
+ * properties stay (J.10).
2295
+ *
2296
+ * The values stay in the file's earlier revisions until a full rewrite: an incremental save
2297
+ * appends the change and keeps the original bytes. When it removed anything, the op's result
2298
+ * says so ([`Applied::still_in_earlier_revisions`](crate::Applied::still_in_earlier_revisions)),
2299
+ * so the caller can offer a full rewrite (on a signed file, the override that removes the
2300
+ * signatures).
2301
+ *
2302
+ * ```
2303
+ * use laminapdf_ops::{MetadataKey, Op, RemoveMetadata};
2304
+ *
2305
+ * let op = Op::from(RemoveMetadata::new(vec![MetadataKey::Authors, MetadataKey::Creator]));
2306
+ * assert_eq!(serde_json::to_string(&op)?, r#"{"op":"removeMetadata","args":{"keys":["authors","creator"]}}"#);
2307
+ * # Ok::<(), serde_json::Error>(())
2308
+ * ```
2309
+ *
2310
+ * Added in 0.2.0.
2311
+ */
2312
+ export interface RemoveMetadata {
2313
+ /**
2314
+ * The fields to remove.
2315
+ */
2316
+ keys: MetadataKey[];
2317
+ /**
2318
+ * As [`SetMetadata::replace_malformed`].
2319
+ */
2320
+ replaceMalformed?: boolean;
2321
+ }
2322
+
2323
+ /**
2324
+ * Renames a named destination, keeping it where it is. With `links: follow` (the default) the
2325
+ * bookmarks, links and `GoTo` actions of this file that name it are renamed too, in the form
2326
+ * they named it in.
2327
+ *
2328
+ * On the wire: `{ "op": "renameNamedDestination", "args": { "from": "sec2", "to": "methods" } }`.
2329
+ *
2330
+ * Added in 0.3.0.
2331
+ */
2332
+ export interface RenameNamedDestination {
2333
+ /**
2334
+ * The current name.
2335
+ */
2336
+ from: string;
2337
+ /**
2338
+ * The new name; no destination may have it yet.
2339
+ */
2340
+ to: string;
2341
+ /**
2342
+ * Whether the uses follow.
2343
+ */
2344
+ links?: RenameLinks;
2345
+ }
2346
+
2347
+ /**
2348
+ * Replaces pages of this document with pages of a source document, pair by pair: the first
2349
+ * source page takes the first target's place, and so on. What pointed at a replaced page
2350
+ * (outline items, links, named destinations, `GoTo` actions, `/OpenAction`) now points at
2351
+ * the page that took its place, with the view `/Fit`, since coordinates on the old page mean
2352
+ * nothing on the new one. Targets left over are deleted (their references retargeted to the
2353
+ * nearest surviving page); source pages left over go after the last copy. The copies come
2354
+ * in as with [`InsertPagesFrom`]; the replaced pages are deleted as with
2355
+ * [`DeletePages`](crate::DeletePages), structure, widgets and earlier revisions included.
2356
+ *
2357
+ * On the wire: `{ "op": "replacePages", "args": { "targets": ["p7.0"], "source": "<64 hex
2358
+ * digits>", "pages": ["p3.0"] } }`, with `carry` optional.
2359
+ *
2360
+ * Added in 0.3.0.
2361
+ */
2362
+ export interface ReplacePages {
2363
+ /**
2364
+ * The pages to replace, in order.
2365
+ */
2366
+ targets: string[];
2367
+ /**
2368
+ * The source document.
2369
+ */
2370
+ source: string;
2371
+ /**
2372
+ * The source's pages that take their places, by their IDs in the source.
2373
+ */
2374
+ pages: string[];
2375
+ /**
2376
+ * What comes along with the pages.
2377
+ */
2378
+ carry?: Carry;
2379
+ }
2380
+
2381
+ /**
2382
+ * Replaces the document's page labels with `ranges`; an empty list removes them, so viewers
2383
+ * show page numbers again.
2384
+ *
2385
+ * Each range starts at a page, named by its ID, and labels that page and the ones after it up
2386
+ * to the next range. The ranges must be in page order, two never on one page, the first on
2387
+ * the document's first page (the number tree must have an entry for page 0, §12.4.2), and
2388
+ * each numbered from 1 or more; otherwise the op fails with `invalid-label-ranges`. Nothing
2389
+ * is written when the catalog already holds exactly these labels
2390
+ * ([`PageLabels::is_written`]); any other tree, a damaged one included, is replaced.
2391
+ *
2392
+ * On the wire:
2393
+ * `{ "op": "setPageLabels", "args": { "ranges": [{ "page": "p3.0", "style": "lowerRoman" }] } }`.
2394
+ *
2395
+ * Added in 0.3.0.
2396
+ */
2397
+ export interface SetPageLabels {
2398
+ /**
2399
+ * The ranges, in page order.
2400
+ */
2401
+ ranges: PageLabelRange[];
2402
+ }
2403
+
2404
+ /**
2405
+ * Replaces the whole XMP packet with `xml`, for what the property ops can't write
2406
+ * (structures, qualifiers, comments). The packet is parsed before it applies and refused if it
2407
+ * doesn't parse (`invalid-xmp-packet`) or changes the PDF/A or PDF/UA identification
2408
+ * (`xmp-claim-read-only`). Info's mirrored entries follow the new packet; in a file that
2409
+ * claims PDF/A, the extension schema entries its properties lack are added and reported
2410
+ * ([`Applied::declared`](crate::Applied::declared)). The old packet stays in the file's
2411
+ * earlier revisions until a full rewrite.
2412
+ *
2413
+ * ```
2414
+ * use laminapdf_ops::{Op, ReplaceXmpPacket};
2415
+ *
2416
+ * let op = Op::from(ReplaceXmpPacket::new("<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">…</x:xmpmeta>"));
2417
+ * assert!(serde_json::to_string(&op)?.starts_with(r#"{"op":"replaceXmpPacket","args":{"xml":"<x:xmpmeta"#));
2418
+ * # Ok::<(), serde_json::Error>(())
2419
+ * ```
2420
+ *
2421
+ * Added in 0.3.0.
2422
+ */
2423
+ export interface ReplaceXmpPacket {
2424
+ /**
2425
+ * The new packet's XML, with or without its `<?xpacket … ?>` wrapper.
2426
+ */
2427
+ xml: string;
2428
+ }
2429
+
2430
+ /**
2431
+ * Reverses the order of `pages` within the places they hold: the first of them (in page
2432
+ * order) takes the last one's place, and so on; the other pages don't move.
2433
+ *
2434
+ * On the wire: `{ "op": "reversePages", "args": { "pages": ["p3.0", "p4.0", "p5.0"] } }`.
2435
+ *
2436
+ * Added in 0.3.0.
2437
+ */
2438
+ export interface ReversePages {
2439
+ /**
2440
+ * The pages; their order here doesn't matter.
2441
+ */
2442
+ pages: string[];
2443
+ }
2444
+
2445
+ /**
2446
+ * Rotates `pages` by `angle`, set or turned ([`RotateMode`]); each page as
2447
+ * [`RotatePage`] does, keeping its object and [`PageId`].
2448
+ *
2449
+ * On the wire: `{ "op": "rotatePages", "args": { "pages": ["p3.0"], "angle": 90, "mode": "turn" } }`.
2450
+ *
2451
+ * Added in 0.3.0.
2452
+ */
2453
+ export interface RotatePages {
2454
+ /**
2455
+ * The pages.
2456
+ */
2457
+ pages: string[];
2458
+ /**
2459
+ * The angle in degrees clockwise: 0, 90, 180 or 270.
2460
+ */
2461
+ angle: 0 | 90 | 180 | 270;
2462
+ /**
2463
+ * Whether the angle is set or added; `set` when left out.
2464
+ */
2465
+ mode?: RotateMode;
2466
+ }
2467
+
1032
2468
  /**
1033
2469
  * Sets a page's rotation to `rotate` (absolute, not relative to the current value).
1034
2470
  *
@@ -1041,18 +2477,74 @@ export type DirectionInit = "ltr" | "rtl";
1041
2477
  * On the wire: `{ "op": "rotatePage", "args": { "page": "p12.0", "rotate": 90 } }`.
1042
2478
  *
1043
2479
  * [ADR 0005]: https://github.com/laudebugs/laminapdf/blob/main/docs/decisions/0005-document-model.md
2480
+ *
2481
+ * Added in 0.2.0.
1044
2482
  */
1045
2483
  export interface RotatePage {
1046
2484
  /**
1047
- * The page.
2485
+ * The page.
2486
+ */
2487
+ page: string;
2488
+ /**
2489
+ * The rotation in degrees clockwise: 0, 90, 180 or 270.
2490
+ */
2491
+ rotate: 0 | 90 | 180 | 270;
2492
+ }
2493
+
2494
+ /**
2495
+ * Sets any XMP property: text, a URI, a number, a boolean, a date, a language alternative,
2496
+ * or an ordered or unordered array of simple values. A file without a packet gets one.
2497
+ *
2498
+ * `prefix` names the namespace when the packet binds no prefix to it. A property the Info
2499
+ * dictionary mirrors (`dc:title`, `pdf:Producer`, …) is set in both, as
2500
+ * [`SetMetadata`](crate::SetMetadata) sets it, and must have its shape: text, or a language
2501
+ * alternative of the `x-default` entry alone, for `dc:title` and `dc:description`; an array of
2502
+ * text for `dc:creator`; a date for the dates.
2503
+ *
2504
+ * ```
2505
+ * use laminapdf_ops::{Op, SetXmpProperty};
2506
+ * use laminapdf_model::xmp::XmpValue;
2507
+ *
2508
+ * let op = Op::from(SetXmpProperty::new("http://example.com/ns/", "acme", "batch", XmpValue::Integer(42)));
2509
+ * assert_eq!(
2510
+ * serde_json::to_string(&op)?,
2511
+ * r#"{"op":"setXmpProperty","args":{"namespace":"http://example.com/ns/","prefix":"acme","name":"batch","value":{"type":"integer","value":42}}}"#
2512
+ * );
2513
+ * # Ok::<(), serde_json::Error>(())
2514
+ * ```
2515
+ *
2516
+ * Added in 0.3.0.
2517
+ */
2518
+ export interface SetXmpProperty {
2519
+ /**
2520
+ * The property's namespace URI.
2521
+ */
2522
+ namespace: string;
2523
+ /**
2524
+ * The prefix to write the namespace with when the packet binds none.
2525
+ */
2526
+ prefix: string;
2527
+ /**
2528
+ * The property's local name.
2529
+ */
2530
+ name: string;
2531
+ /**
2532
+ * The new value.
1048
2533
  */
1049
- page: string;
2534
+ value: XmpValue;
1050
2535
  /**
1051
- * The rotation in degrees clockwise: 0, 90, 180 or 270.
2536
+ * As [`SetMetadata::replace_malformed`](crate::SetMetadata::replace_malformed).
1052
2537
  */
1053
- rotate: 0 | 90 | 180 | 270;
2538
+ replaceMalformed?: boolean;
1054
2539
  }
1055
2540
 
2541
+ /**
2542
+ * Something in the file that names a destination.
2543
+ *
2544
+ * Added in 0.3.0.
2545
+ */
2546
+ export type DestinationUse = { kind: "outlineItem"; item: string } | { kind: "annotation"; page: string; annot: string } | { kind: "catalog" };
2547
+
1056
2548
  /**
1057
2549
  * Text rendering (`Tr`).
1058
2550
  */
@@ -1141,11 +2633,31 @@ export interface MetadataInit {
1141
2633
  modDate?: string;
1142
2634
  }
1143
2635
 
2636
+ /**
2637
+ * The document's XMP packet as text (`laminapdf::XmpText`).
2638
+ */
2639
+ export interface XmpTextJs {
2640
+ /**
2641
+ * Whether there is a packet, and whether it was read.
2642
+ */
2643
+ status: PacketStatus;
2644
+ /**
2645
+ * The packet's XML, with the edits made so far.
2646
+ */
2647
+ xml?: string;
2648
+ /**
2649
+ * The PDF/A part and conformance the packet claims, e.g. `"2B"`.
2650
+ */
2651
+ pdfa?: string;
2652
+ }
2653
+
1144
2654
  /**
1145
2655
  * The kind of change an op makes. The save planner checks it against `DocMDP` / `FieldMDP`
1146
2656
  * permissions and the document's `SaveConstraint` ([ADR 0007]).
1147
2657
  *
1148
2658
  * [ADR 0007]: https://github.com/laudebugs/laminapdf/blob/main/docs/decisions/0007-save-planner.md
2659
+ *
2660
+ * Added in 0.2.0.
1149
2661
  */
1150
2662
  export type ModificationClass = "metadata" | "formFill" | "annotation" | "signature" | "pageStructure" | "content" | "document";
1151
2663
 
@@ -1171,6 +2683,22 @@ export interface ModelsInit {
1171
2683
  langs?: string[];
1172
2684
  }
1173
2685
 
2686
+ /**
2687
+ * The page and zoom a document opens at.
2688
+ *
2689
+ * Added in 0.3.0.
2690
+ */
2691
+ export interface OpenAt {
2692
+ /**
2693
+ * The page.
2694
+ */
2695
+ page: string;
2696
+ /**
2697
+ * The zoom.
2698
+ */
2699
+ zoom?: "default" | "fitPage" | "fitWidth" | number;
2700
+ }
2701
+
1174
2702
  /**
1175
2703
  * The pages a Markdown document flows through.
1176
2704
  */
@@ -1205,11 +2733,80 @@ export interface EditedJs {
1205
2733
  * IDs of the pages whose content or attributes changed.
1206
2734
  */
1207
2735
  touchedPages: string[];
2736
+ /**
2737
+ * A metadata edit rewrote the XMP packet whole (UTF-16, or marked read-only).
2738
+ */
2739
+ packetRewritten: boolean;
2740
+ /**
2741
+ * A metadata edit removed values the file's earlier revisions still hold, which only a
2742
+ * full rewrite drops.
2743
+ */
2744
+ stillInEarlierRevisions: boolean;
2745
+ /**
2746
+ * IDs of annotations an annotation op deleted besides the one it names (Popups, replies,
2747
+ * the rest of a group); left out when there are none.
2748
+ */
2749
+ alsoDeleted?: string[];
1208
2750
  /**
1209
2751
  * Whether the edit changed the document: one that only set values they already had leaves
1210
2752
  * no step to undo.
1211
2753
  */
1212
2754
  changed: boolean;
2755
+ /**
2756
+ * The IDs of the bookmarks the edit added, in order.
2757
+ */
2758
+ createdOutlineItems: string[];
2759
+ /**
2760
+ * An outline edit found the outline's links broken and rewrote them whole; bookmarks
2761
+ * stored inside others have new IDs.
2762
+ */
2763
+ outlineRepaired: boolean;
2764
+ /**
2765
+ * What still names a named destination the edit deleted.
2766
+ */
2767
+ destinationUses: DestinationUse[];
2768
+ /**
2769
+ * The XMP properties the edit declared in a PDF/A file's extension schemas.
2770
+ */
2771
+ declared: ExtensionPropertyJs[];
2772
+ /**
2773
+ * The page IDs in order after the edit, when it changed the page list.
2774
+ */
2775
+ pageOrder?: string[];
2776
+ /**
2777
+ * What a page deletion did to the references to the deleted pages.
2778
+ */
2779
+ references: ReferenceEditJs[];
2780
+ /**
2781
+ * What a page duplication did to the form fields whose widgets the copied pages show;
2782
+ * left out when there are none.
2783
+ */
2784
+ fields?: FieldEditJs[];
2785
+ /**
2786
+ * The copies a page duplication made whose tags couldn't all be cloned; left out when
2787
+ * there are none.
2788
+ */
2789
+ tagsIncomplete?: string[];
2790
+ /**
2791
+ * The page holding each link a page copied in from another document lost, one entry per
2792
+ * link; left out when there are none.
2793
+ */
2794
+ linksRemoved?: string[];
2795
+ /**
2796
+ * The pages copied in from another document without the tags their source gave them; left
2797
+ * out when there are none.
2798
+ */
2799
+ tagsDropped?: string[];
2800
+ /**
2801
+ * The named destinations a merge or a page import brought in under another name, because
2802
+ * the document already used theirs; left out when there are none.
2803
+ */
2804
+ renamedDestinations?: RenamedDestinationJs[];
2805
+ /**
2806
+ * The bookmarks a merge left out because the pages they went to didn't come along; left
2807
+ * out when there are none.
2808
+ */
2809
+ bookmarksDropped?: number;
1213
2810
  }
1214
2811
 
1215
2812
  /**
@@ -1222,11 +2819,70 @@ export type PageModeInit = "none" | "outlines" | "thumbnails" | "fullScreen" | "
1222
2819
  */
1223
2820
  export type SaveModeJs = "auto" | "incremental" | "fullRewrite";
1224
2821
 
2822
+ /**
2823
+ * The wire form, under the name TypeScript gives it.
2824
+ */
2825
+ export type XmpValue = { type: "text"; value: string } | { type: "uri"; value: string } | { type: "integer"; value: number } | { type: "real"; value: number } | { type: "boolean"; value: boolean } | { type: "date"; value: string } | { type: "langAlt"; value: XmpLangText[] } | { type: "seq"; value: XmpValue[] } | { type: "bag"; value: XmpValue[] };
2826
+
2827
+ /**
2828
+ * The yes-or-no window entries of the viewer preferences.
2829
+ */
2830
+ export interface WindowPreferencesJs {
2831
+ /**
2832
+ * Hide the reader's toolbars.
2833
+ */
2834
+ hideToolbar: boolean;
2835
+ /**
2836
+ * Hide the reader's menu bar.
2837
+ */
2838
+ hideMenubar: boolean;
2839
+ /**
2840
+ * Hide the scroll bars and navigation controls.
2841
+ */
2842
+ hideWindowUi: boolean;
2843
+ /**
2844
+ * Resize the window to fit the first page.
2845
+ */
2846
+ fitWindow: boolean;
2847
+ /**
2848
+ * Put the window in the middle of the screen.
2849
+ */
2850
+ centerWindow: boolean;
2851
+ /**
2852
+ * Show the document's title in the title bar.
2853
+ */
2854
+ displayDocTitle: boolean;
2855
+ }
2856
+
2857
+ /**
2858
+ * What [`DeleteOutlineItem`](super::DeleteOutlineItem) does with the item's children.
2859
+ *
2860
+ * Added in 0.3.0.
2861
+ */
2862
+ export type ChildItems = "delete" | "promote";
2863
+
2864
+ /**
2865
+ * What [`DeletePages`] does with a destination that names a deleted page.
2866
+ *
2867
+ * Added in 0.3.0.
2868
+ */
2869
+ export type ReferencePolicy = "retarget" | "remove";
2870
+
1225
2871
  /**
1226
2872
  * What `WasmDocument.extract` returns.
1227
2873
  */
1228
2874
  export type ExtractFormat = "markdown" | "json" | "text" | "chunks";
1229
2875
 
2876
+ /**
2877
+ * What `flow` added.
2878
+ */
2879
+ export interface FlowReportJs {
2880
+ /**
2881
+ * The pages it added, in order, by ID.
2882
+ */
2883
+ pages: string[];
2884
+ }
2885
+
1230
2886
  /**
1231
2887
  * What `markdown` added.
1232
2888
  */
@@ -1298,6 +2954,33 @@ export interface PermissionsJs {
1298
2954
  assemble: boolean;
1299
2955
  }
1300
2956
 
2957
+ /**
2958
+ * What a page duplication or a page copied in did to one form field.
2959
+ */
2960
+ export interface FieldEditJs {
2961
+ /**
2962
+ * The field on the source page (in the source document, for a page copied in).
2963
+ */
2964
+ field: string;
2965
+ /**
2966
+ * The copy whose widget it concerns.
2967
+ */
2968
+ page: string;
2969
+ /**
2970
+ * `renamed` (the copy's widget belongs to a new field), `linked` (it joined the field of
2971
+ * the same name) or `notCopied` (a signature's widget).
2972
+ */
2973
+ outcome: "renamed" | "linked" | "notCopied";
2974
+ /**
2975
+ * The new field's ID, when renamed; the field it joined, when linked.
2976
+ */
2977
+ to?: string;
2978
+ /**
2979
+ * The new field's fully qualified name, when renamed.
2980
+ */
2981
+ name?: string;
2982
+ }
2983
+
1301
2984
  /**
1302
2985
  * What a run measures.
1303
2986
  */
@@ -1350,6 +3033,24 @@ export interface SaveReportJs {
1350
3033
  * Whether encryption was removed.
1351
3034
  */
1352
3035
  encryptionRemoved: boolean;
3036
+ /**
3037
+ * Whether the save stamped the save-time metadata (`metadataDate`, `instanceId`).
3038
+ */
3039
+ metadataUpdated: boolean;
3040
+ /**
3041
+ * Whether the options asked for the stamp and the save left it out, because it would have
3042
+ * broken a signature's restriction the saved changes keep.
3043
+ */
3044
+ metadataNotUpdated: boolean;
3045
+ /**
3046
+ * Whether an edit saved here rewrote the XMP packet whole.
3047
+ */
3048
+ packetRewritten: boolean;
3049
+ /**
3050
+ * Whether the save emptied the undo history (a full rewrite, or an incremental save that
3051
+ * freed objects); for a copy, whether adopting it would.
3052
+ */
3053
+ historyCleared: boolean;
1353
3054
  }
1354
3055
 
1355
3056
  /**
@@ -1371,11 +3072,44 @@ export interface RevertedJs {
1371
3072
  touchedPages: string[];
1372
3073
  }
1373
3074
 
3075
+ /**
3076
+ * What becomes of the sources' outlines (bookmarks) in a merge.
3077
+ *
3078
+ * Added in 0.3.0.
3079
+ */
3080
+ export type OutlineMerge = "perFile" | "keep" | "none";
3081
+
3082
+ /**
3083
+ * What comes along with pages copied from another document.
3084
+ *
3085
+ * Added in 0.3.0.
3086
+ */
3087
+ export interface Carry {
3088
+ /**
3089
+ * Whether the pages' annotations other than form fields come along (links, comments,
3090
+ * markup); `true` when left out.
3091
+ */
3092
+ annotations?: boolean;
3093
+ /**
3094
+ * What happens to a form field whose name the target already uses; `rename` when left
3095
+ * out.
3096
+ */
3097
+ fields?: FieldClash;
3098
+ }
3099
+
1374
3100
  /**
1375
3101
  * What following a link does, by `kind`.
1376
3102
  */
1377
3103
  export type LinkToJs = { kind: "dest"; target?: TargetJs } | { kind: "named"; name: string; target?: TargetJs } | { kind: "uri"; uri: string } | { kind: "remote"; file?: string } | { kind: "named-action"; name: string } | { kind: "unsupported"; action: string };
1378
3104
 
3105
+ /**
3106
+ * What happens to a copied form field whose fully qualified name the target already uses
3107
+ * (E2 plan §11).
3108
+ *
3109
+ * Added in 0.3.0.
3110
+ */
3111
+ export type FieldClash = "rename" | "link";
3112
+
1379
3113
  /**
1380
3114
  * What happens to hidden text and page furniture.
1381
3115
  */
@@ -1396,6 +3130,25 @@ export interface DropInit {
1396
3130
  */
1397
3131
  export type OverflowInit = "clip" | "error";
1398
3132
 
3133
+ /**
3134
+ * What the document's `/Metadata` holds.
3135
+ *
3136
+ * Added in 0.2.0.
3137
+ */
3138
+ export type PacketStatus = "absent" | "parsed" | "malformed";
3139
+
3140
+ /**
3141
+ * Where a bookmark goes.
3142
+ *
3143
+ * Added in 0.3.0.
3144
+ */
3145
+ export type OutlineTarget = { destination: ExplicitDestination } | { named: string } | { uri: string };
3146
+
3147
+ /**
3148
+ * Where a document opens, by `kind`.
3149
+ */
3150
+ export type OpenTargetJs = { kind: "default" } | { kind: "page"; target: TargetJs } | { kind: "action"; action: string };
3151
+
1399
3152
  /**
1400
3153
  * Where a link or outline item goes.
1401
3154
  */
@@ -1411,6 +3164,21 @@ export type SplitOnName = "headings" | "blocks" | "pages";
1411
3164
  */
1412
3165
  export type ReadingOrderName = "auto" | "tagged" | "layout" | "content-stream";
1413
3166
 
3167
+ /**
3168
+ * Whether [`RenameNamedDestination`](super::RenameNamedDestination) renames the uses of the
3169
+ * name in this file too.
3170
+ *
3171
+ * Added in 0.3.0.
3172
+ */
3173
+ export type RenameLinks = "keep" | "follow";
3174
+
3175
+ /**
3176
+ * Which side [`DocumentMetadata`]'s values come from.
3177
+ *
3178
+ * Added in 0.2.0.
3179
+ */
3180
+ export type MetadataSource = "info" | "xmp";
3181
+
1414
3182
  /**
1415
3183
  * Which table detectors run.
1416
3184
  */
@@ -1514,6 +3282,18 @@ export class WasmBuilder {
1514
3282
  * `invalid-page-labels`, `invalid-geometry`, `subset-failed`.
1515
3283
  */
1516
3284
  finish(): WasmDocument;
3285
+ /**
3286
+ * Lays `document` out as tagged pages that flow, after any pages already added, filled from
3287
+ * `options.data` first when it is given. The document's profiles are the builder's to set
3288
+ * (`profiles` in its options); its warnings are the finished document's.
3289
+ *
3290
+ * # Errors
3291
+ * `builder-finished`; `unknown-option`, `invalid-argument`; `invalid-document` with the JSON
3292
+ * Pointer at fault and the closest keys in `didYouMean`; `template-data-missing`,
3293
+ * `template-data-type`, `template-too-large`; `unknown-font` and `unknown-image` for a name
3294
+ * `resources` lacks; `missing-glyph`, `flow-content-too-large`.
3295
+ */
3296
+ flow(document: unknown, resources: WasmFlowResources, options: FlowOptionsInit | undefined): FlowReportJs;
1517
3297
  /**
1518
3298
  * Loads a font from its bytes (TrueType or OpenType/CFF) and registers it; it is
1519
3299
  * subset to the glyphs drawn.
@@ -1604,6 +3384,24 @@ export class WasmDocument {
1604
3384
  private constructor();
1605
3385
  free(): void;
1606
3386
  [Symbol.dispose](): void;
3387
+ /**
3388
+ * Adds another PDF as a source document: `{ id, pages }`, its ID (64 hex digits, the
3389
+ * SHA-256 of `bytes`) and its page IDs in order. An encrypted one opens with `password`,
3390
+ * which no op ever holds.
3391
+ *
3392
+ * # Errors
3393
+ * `wrong-password`, `password-required`, and the errors of a file that doesn't open.
3394
+ */
3395
+ addSource(bytes: Uint8Array, password?: string | null): { id: string; pages: string[] };
3396
+ /**
3397
+ * Makes `bytes`, the whole output of `saveCopy`, the document's saved file (it rebases onto
3398
+ * them), once they are written where the document lives; `historyCleared` is the copy's
3399
+ * report's.
3400
+ *
3401
+ * # Errors
3402
+ * `nested-transaction`, `saved-not-rebased`; `not-rebased` when `bytes` can't be read.
3403
+ */
3404
+ adoptCopy(bytes: Uint8Array, historyCleared: boolean): void;
1607
3405
  /**
1608
3406
  * Applies an op log (`{ "v": 1, "ops": [ … ] }`) as one transaction.
1609
3407
  *
@@ -1619,6 +3417,14 @@ export class WasmDocument {
1619
3417
  * error (nothing is applied).
1620
3418
  */
1621
3419
  apply(ops: Op[]): EditedJs;
3420
+ /**
3421
+ * `view` (page space) on page `page` as the destination the outline and named-destination
3422
+ * ops take, in the page's user space (the extract and text modules).
3423
+ *
3424
+ * # Errors
3425
+ * `invalid-argument` for a view that isn't one; `page-index-out-of-range`; reading errors.
3426
+ */
3427
+ destinationAt(page: number, view: TargetViewJs): ExplicitDestination;
1622
3428
  /**
1623
3429
  * An extraction stepped a page at a time, whose models the host runs: each step returns
1624
3430
  * its progress, with the result it waits for under `request` (render that page at `dpi`,
@@ -1629,6 +3435,14 @@ export class WasmDocument {
1629
3435
  * As `extract`, for the options and the pages asked for.
1630
3436
  */
1631
3437
  extractJob(options: ExtractInit): WasmExtractJob;
3438
+ /**
3439
+ * A new document of `pages` of this one, in the order given.
3440
+ *
3441
+ * # Errors
3442
+ * `invalid-argument` for a value that isn't a list of page IDs, `unknown-page`; reading
3443
+ * errors.
3444
+ */
3445
+ extractPages(pages: string[]): WasmDocument;
1632
3446
  /**
1633
3447
  * The document's text for retrieval and LLMs, as one string: Markdown, plain text, the
1634
3448
  * `laminapdf.extract/1` JSON, or the chunks as a JSON array (the extract and text modules).
@@ -1649,6 +3463,13 @@ export class WasmDocument {
1649
3463
  * Reading errors.
1650
3464
  */
1651
3465
  info(): DocumentInfoJs;
3466
+ /**
3467
+ * How the document asks to be shown when it opens (the extract and text modules).
3468
+ *
3469
+ * # Errors
3470
+ * `data-pending` and the reading errors.
3471
+ */
3472
+ initialView(): InitialViewJs;
1652
3473
  /**
1653
3474
  * Whether the file is encrypted (it opened with its password, or the empty one).
1654
3475
  */
@@ -1660,6 +3481,24 @@ export class WasmDocument {
1660
3481
  * Reading errors.
1661
3482
  */
1662
3483
  isTagged(): boolean;
3484
+ /**
3485
+ * A new document of `inputs` (each `{ bytes, password?, title? }`) one after another,
3486
+ * with their bookmarks, named destinations, form fields, layers and page labels; `options`
3487
+ * as `mergeDocuments`' (`outline`, `fields`).
3488
+ *
3489
+ * # Errors
3490
+ * `invalid-argument` / `unknown-option` for bad values, `wrong-password`,
3491
+ * `password-required`, and the errors of a file that doesn't open.
3492
+ */
3493
+ static merge(inputs: { bytes: Uint8Array; password?: string; title?: string }[], options: MergeOptions | undefined): WasmDocument;
3494
+ /**
3495
+ * The document's metadata, read from Info and XMP together, with the fields where they
3496
+ * disagree.
3497
+ *
3498
+ * # Errors
3499
+ * Reading errors.
3500
+ */
3501
+ metadata(): DocumentMetadata;
1663
3502
  /**
1664
3503
  * The named destination `name`, or `undefined` when the document has none by that name or
1665
3504
  * it names no page here (the extract and text modules).
@@ -1668,6 +3507,13 @@ export class WasmDocument {
1668
3507
  * `data-pending` and the reading errors.
1669
3508
  */
1670
3509
  namedDestination(name: string): TargetJs | undefined;
3510
+ /**
3511
+ * Every named destination, sorted by name (the extract and text modules).
3512
+ *
3513
+ * # Errors
3514
+ * `data-pending` and the reading errors.
3515
+ */
3516
+ namedDestinations(): NamedDestinationJs[];
1671
3517
  /**
1672
3518
  * Opens a document from its bytes.
1673
3519
  *
@@ -1693,6 +3539,14 @@ export class WasmDocument {
1693
3539
  * `data-pending` and the reading errors.
1694
3540
  */
1695
3541
  outline(): OutlineNodeJs[];
3542
+ /**
3543
+ * The annotations on page `index`, in the order of its `/Annots`, every subtype included
3544
+ * (the extract and text modules).
3545
+ *
3546
+ * # Errors
3547
+ * `page-index-out-of-range`, `data-pending` and the reading errors.
3548
+ */
3549
+ pageAnnotations(index: number): PageAnnotationJs[];
1696
3550
  /**
1697
3551
  * A handle on the page with `id` (`p12.0`).
1698
3552
  *
@@ -1735,6 +3589,13 @@ export class WasmDocument {
1735
3589
  * `page-index-out-of-range`; reading errors.
1736
3590
  */
1737
3591
  page(index: number): WasmPage;
3592
+ /**
3593
+ * How a save with `options` would go, without saving.
3594
+ *
3595
+ * # Errors
3596
+ * `invalid-argument` / `unknown-option` for bad options; reading errors.
3597
+ */
3598
+ plan(options: SaveOptionsInit | undefined): PlannedSaveJs;
1738
3599
  /**
1739
3600
  * The document's properties (the extract and text modules). Reads every object once.
1740
3601
  *
@@ -1757,6 +3618,14 @@ export class WasmDocument {
1757
3618
  * As [`WasmDocument::undo`].
1758
3619
  */
1759
3620
  redo(): RevertedJs | undefined;
3621
+ /**
3622
+ * Writes what `save` would and leaves the document as it was: not rebased, its changes
3623
+ * still unsaved, the save-time stamp in the copy only (Save a copy).
3624
+ *
3625
+ * # Errors
3626
+ * As `save`; the document is unchanged either way.
3627
+ */
3628
+ saveCopy(options: SaveOptionsInit | undefined): { bytes: Uint8Array<ArrayBuffer>; report: SaveReportJs };
1760
3629
  /**
1761
3630
  * A save as a job, stepped with a budget of work units (ADR 0028 §3, §4).
1762
3631
  *
@@ -1771,6 +3640,17 @@ export class WasmDocument {
1771
3640
  * The save's errors (`would-invalidate-signatures`, `requires-rewrite`, …).
1772
3641
  */
1773
3642
  save(options: SaveOptionsInit | undefined): { bytes: Uint8Array<ArrayBuffer>; report: SaveReportJs };
3643
+ /**
3644
+ * This document cut into new ones: `{ count: n }` parts of `n` pages, `{ ranges: [[id, …],
3645
+ * …] }` one part per list of page IDs, or `{ bookmarks: level }` a part from each bookmark
3646
+ * at that depth (1: the top level). Each part carries what its pages reach and the
3647
+ * bookmarks that go to them.
3648
+ *
3649
+ * # Errors
3650
+ * `invalid-argument` / `unknown-option` for a value that isn't one of those, `unknown-page`,
3651
+ * `no-pages-left` for an empty list; reading errors.
3652
+ */
3653
+ split(by: { readonly count: number } | { readonly ranges: readonly (readonly string[])[] } | { readonly bookmarks: number }): WasmDocument[];
1774
3654
  /**
1775
3655
  * The structure tree's top-level elements in reading order, or `undefined` without one (the
1776
3656
  * extract and text modules, beside `WasmPage.text`, whose runs it links by MCID).
@@ -1779,6 +3659,13 @@ export class WasmDocument {
1779
3659
  * Reading errors.
1780
3660
  */
1781
3661
  structureTree(): StructureNodeJs[] | undefined;
3662
+ /**
3663
+ * The document's article threads; empty without any (the extract and text modules).
3664
+ *
3665
+ * # Errors
3666
+ * `data-pending` and the reading errors.
3667
+ */
3668
+ threads(): ThreadJs[];
1782
3669
  /**
1783
3670
  * Undoes the newest transaction: how it went and the pages it touched; `undefined` when
1784
3671
  * there is nothing to undo.
@@ -1791,6 +3678,20 @@ export class WasmDocument {
1791
3678
  * A cursor over the warnings so far (build warnings first), each as the §1 object.
1792
3679
  */
1793
3680
  warnings(): WasmWarningCursor;
3681
+ /**
3682
+ * The signature restrictions `op` would break if it were applied and saved.
3683
+ *
3684
+ * # Errors
3685
+ * `invalid-argument` for a value that isn't an op; reading errors.
3686
+ */
3687
+ wouldViolate(op: Op): ViolationJs[];
3688
+ /**
3689
+ * The document's XMP packet as text, with the edits made so far.
3690
+ *
3691
+ * # Errors
3692
+ * Reading errors.
3693
+ */
3694
+ xmpPacket(): XmpTextJs;
1794
3695
  }
1795
3696
 
1796
3697
  /**
@@ -1825,6 +3726,26 @@ export class WasmExtractJob {
1825
3726
  step(budget: number): ({ state: "progress" } & ExtractProgressJs) | { state: "done"; output: string };
1826
3727
  }
1827
3728
 
3729
+ /**
3730
+ * The fonts and images a document names, by the names it gives them.
3731
+ */
3732
+ export class WasmFlowResources {
3733
+ free(): void;
3734
+ [Symbol.dispose](): void;
3735
+ /**
3736
+ * `font` for the styles that name `name`; the same name again replaces it.
3737
+ */
3738
+ font(name: string, font: WasmFont): void;
3739
+ /**
3740
+ * `image` for the figures that name `name`; the same name again replaces it.
3741
+ */
3742
+ image(name: string, image: WasmImage): void;
3743
+ /**
3744
+ * No fonts and no images.
3745
+ */
3746
+ constructor();
3747
+ }
3748
+
1828
3749
  /**
1829
3750
  * A font registered with a [`WasmBuilder`].
1830
3751
  */
@@ -1884,6 +3805,23 @@ export class WasmImage {
1884
3805
  readonly width: number;
1885
3806
  }
1886
3807
 
3808
+ /**
3809
+ * The images of [`images_to_pdf`], in page order. Images are JavaScript-owned objects, which a
3810
+ * record can't carry, so they are added one by one.
3811
+ */
3812
+ export class WasmImageList {
3813
+ free(): void;
3814
+ [Symbol.dispose](): void;
3815
+ /**
3816
+ * An empty list.
3817
+ */
3818
+ constructor();
3819
+ /**
3820
+ * Adds `image` as the next page. The image stays usable: the list holds its own copy.
3821
+ */
3822
+ push(image: WasmImage): void;
3823
+ }
3824
+
1887
3825
  /**
1888
3826
  * The fonts and images of a Markdown build, by role and by the target the Markdown names.
1889
3827
  */
@@ -2231,6 +4169,16 @@ export function allocationFailed(): boolean;
2231
4169
  */
2232
4170
  export function hasText(): boolean;
2233
4171
 
4172
+ /**
4173
+ * A new document with one page per image of `images`, in order: a JPEG embedded as it is, a PNG
4174
+ * with its transparency, each drawn the way up its EXIF orientation says.
4175
+ *
4176
+ * # Errors
4177
+ * `invalid-geometry` for no images, a negative margin or resolution, or a page too small for its
4178
+ * margins; `unknown-option`, `invalid-argument` for bad options.
4179
+ */
4180
+ export function imagesToPdf(images: WasmImageList, options: ImagesOptionsInit | undefined): WasmDocument;
4181
+
2234
4182
  /**
2235
4183
  * The crate version (`@laminapdf/wasm`'s).
2236
4184
  */
@@ -2243,8 +4191,10 @@ export interface InitOutput {
2243
4191
  readonly __wbg_wasmbuilder_free: (a: number, b: number) => void;
2244
4192
  readonly __wbg_wasmdocument_free: (a: number, b: number) => void;
2245
4193
  readonly __wbg_wasmextractjob_free: (a: number, b: number) => void;
4194
+ readonly __wbg_wasmflowresources_free: (a: number, b: number) => void;
2246
4195
  readonly __wbg_wasmfont_free: (a: number, b: number) => void;
2247
4196
  readonly __wbg_wasmimage_free: (a: number, b: number) => void;
4197
+ readonly __wbg_wasmimagelist_free: (a: number, b: number) => void;
2248
4198
  readonly __wbg_wasmmarkdownoptions_free: (a: number, b: number) => void;
2249
4199
  readonly __wbg_wasmpage_free: (a: number, b: number) => void;
2250
4200
  readonly __wbg_wasmpagebuilder_free: (a: number, b: number) => void;
@@ -2253,10 +4203,12 @@ export interface InitOutput {
2253
4203
  readonly __wbg_wasmwarningcursor_free: (a: number, b: number) => void;
2254
4204
  readonly allocationFailed: () => number;
2255
4205
  readonly hasText: () => number;
4206
+ readonly imagesToPdf: (a: number, b: any) => [number, number, number];
2256
4207
  readonly version: () => [number, number];
2257
4208
  readonly wasmbuilder_attach: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: any) => [number, number];
2258
4209
  readonly wasmbuilder_destination: (a: number, b: number, c: number, d: number, e: any) => [number, number];
2259
4210
  readonly wasmbuilder_finish: (a: number) => [number, number, number];
4211
+ readonly wasmbuilder_flow: (a: number, b: any, c: number, d: any) => [number, number, number];
2260
4212
  readonly wasmbuilder_fontBytes: (a: number, b: number, c: number) => [number, number, number];
2261
4213
  readonly wasmbuilder_fontCollection: (a: number, b: number, c: number, d: number) => [number, number, number];
2262
4214
  readonly wasmbuilder_lang: (a: number, b: number, c: number) => [number, number];
@@ -2268,35 +4220,53 @@ export interface InitOutput {
2268
4220
  readonly wasmbuilder_pageLabels: (a: number, b: any) => [number, number];
2269
4221
  readonly wasmbuilder_standardFont: (a: number, b: number, c: number) => [number, number, number];
2270
4222
  readonly wasmbuilder_viewerPreferences: (a: number, b: any) => [number, number];
4223
+ readonly wasmdocument_addSource: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
4224
+ readonly wasmdocument_adoptCopy: (a: number, b: number, c: number, d: number) => [number, number];
2271
4225
  readonly wasmdocument_apply: (a: number, b: any) => [number, number, number];
2272
4226
  readonly wasmdocument_applyLog: (a: number, b: number, c: number) => [number, number, number];
4227
+ readonly wasmdocument_destinationAt: (a: number, b: number, c: any) => [number, number, number];
2273
4228
  readonly wasmdocument_extract: (a: number, b: any) => [number, number, number, number];
2274
4229
  readonly wasmdocument_extractJob: (a: number, b: any) => [number, number, number];
4230
+ readonly wasmdocument_extractPages: (a: number, b: any) => [number, number, number];
2275
4231
  readonly wasmdocument_hasUnsavedChanges: (a: number) => number;
2276
4232
  readonly wasmdocument_info: (a: number) => [number, number, number];
4233
+ readonly wasmdocument_initialView: (a: number) => [number, number, number];
2277
4234
  readonly wasmdocument_isEncrypted: (a: number) => number;
2278
4235
  readonly wasmdocument_isTagged: (a: number) => [number, number, number];
4236
+ readonly wasmdocument_merge: (a: any, b: any) => [number, number, number];
4237
+ readonly wasmdocument_metadata: (a: number) => [number, number, number];
2279
4238
  readonly wasmdocument_namedDestination: (a: number, b: number, c: number) => [number, number, number];
4239
+ readonly wasmdocument_namedDestinations: (a: number) => [number, number, number];
2280
4240
  readonly wasmdocument_openBytes: (a: number, b: number, c: any) => [number, number, number];
2281
4241
  readonly wasmdocument_openSource: (a: number, b: any) => [number, number, number];
2282
4242
  readonly wasmdocument_outline: (a: number) => [number, number, number];
2283
4243
  readonly wasmdocument_page: (a: number, b: number) => [number, number, number];
4244
+ readonly wasmdocument_pageAnnotations: (a: number, b: number) => [number, number, number];
2284
4245
  readonly wasmdocument_pageById: (a: number, b: number, c: number) => [number, number, number];
2285
4246
  readonly wasmdocument_pageCount: (a: number) => [number, number, number];
2286
4247
  readonly wasmdocument_pageInfo: (a: number, b: number) => [number, number, number];
2287
4248
  readonly wasmdocument_pageInfos: (a: number) => [number, number, number];
2288
4249
  readonly wasmdocument_pageLinks: (a: number, b: number) => [number, number, number];
4250
+ readonly wasmdocument_plan: (a: number, b: any) => [number, number, number];
2289
4251
  readonly wasmdocument_properties: (a: number) => [number, number, number];
2290
4252
  readonly wasmdocument_rebase: (a: number, b: number, c: number) => [number, number];
2291
4253
  readonly wasmdocument_redo: (a: number) => [number, number, number];
2292
4254
  readonly wasmdocument_save: (a: number, b: any) => [number, number, number];
4255
+ readonly wasmdocument_saveCopy: (a: number, b: any) => [number, number, number];
2293
4256
  readonly wasmdocument_saveJob: (a: number, b: any) => [number, number, number];
4257
+ readonly wasmdocument_split: (a: number, b: any) => [number, number, number];
2294
4258
  readonly wasmdocument_structureTree: (a: number) => [number, number, number];
4259
+ readonly wasmdocument_threads: (a: number) => [number, number, number];
2295
4260
  readonly wasmdocument_undo: (a: number) => [number, number, number];
2296
4261
  readonly wasmdocument_warnings: (a: number) => number;
4262
+ readonly wasmdocument_wouldViolate: (a: number, b: any) => [number, number, number];
4263
+ readonly wasmdocument_xmpPacket: (a: number) => [number, number, number];
2297
4264
  readonly wasmextractjob_cancel: (a: number) => void;
2298
4265
  readonly wasmextractjob_provide: (a: number, b: any) => [number, number];
2299
4266
  readonly wasmextractjob_step: (a: number, b: number) => [number, number, number];
4267
+ readonly wasmflowresources_font: (a: number, b: number, c: number, d: number) => void;
4268
+ readonly wasmflowresources_image: (a: number, b: number, c: number, d: number) => void;
4269
+ readonly wasmflowresources_new: () => number;
2300
4270
  readonly wasmfont_family: (a: number) => [number, number];
2301
4271
  readonly wasmfont_isStandard: (a: number) => number;
2302
4272
  readonly wasmfont_postscriptName: (a: number) => [number, number];
@@ -2305,6 +4275,8 @@ export interface InitOutput {
2305
4275
  readonly wasmimage_png: (a: number, b: number) => [number, number, number];
2306
4276
  readonly wasmimage_rgba: (a: number, b: number, c: number, d: number) => [number, number, number];
2307
4277
  readonly wasmimage_width: (a: number) => number;
4278
+ readonly wasmimagelist_new: () => number;
4279
+ readonly wasmimagelist_push: (a: number, b: number) => void;
2308
4280
  readonly wasmmarkdownoptions_font: (a: number, b: number, c: number, d: number) => [number, number];
2309
4281
  readonly wasmmarkdownoptions_image: (a: number, b: number, c: number, d: number) => void;
2310
4282
  readonly wasmmarkdownoptions_new: () => number;
@@ -2350,8 +4322,8 @@ export interface InitOutput {
2350
4322
  readonly __wbindgen_exn_store: (a: number) => void;
2351
4323
  readonly __externref_table_alloc: () => number;
2352
4324
  readonly __wbindgen_externrefs: WebAssembly.Table;
2353
- readonly __wbindgen_free: (a: number, b: number, c: number) => void;
2354
4325
  readonly __externref_table_dealloc: (a: number) => void;
4326
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
2355
4327
  readonly __wbindgen_start: () => void;
2356
4328
  }
2357
4329