Skip to content

Commit 069f249

Browse files
committed
✨ Support relationship property for embedded files
The `AFRelationship` key in the PDF file specification dictionary can be used to indicate the role of an embedded file in the context of the document. This key is required for PDF/A documents. This commit adds support for a `relationship` property of an embedded file to set it.
1 parent 2eb3dc5 commit 069f249

File tree

4 files changed

+57
-6
lines changed

4 files changed

+57
-6
lines changed

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -603,14 +603,18 @@ archival purposes. Those files can be added to the document using the
603603
representing a file with the following properties:
604604
605605
- `content`: The binary content of the file as a `Uint8Array`.
606-
- `fileName`: The name of the file as it will appear in the
607-
list of attachments in the PDF viewer.
606+
- `fileName`: The name of the file as it will appear in the list of
607+
attachments in the PDF viewer.
608608
- `mimeType`: The MIME type of the file.
609609
- `description` (optional): A brief description of the file's content or
610610
purpose. This information can be displayed to the user in the PDF
611611
viewer.
612-
- `creationDate` (optional): The date and time when the file was created.
613-
- `modificationDate` (optional): The date and time when the file was last
612+
- `creationDate` (optional): The date and time when the file was
613+
created.
614+
- `modificationDate` (optional): The date and time when the file was
615+
last modified.
616+
- `relationship` (optional): A name that specifies the relationship
617+
between the file and the document.
614618
615619
```ts
616620
const document = {

src/api/document.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,27 @@ export type DocumentDefinition = {
101101
};
102102
};
103103

104+
/**
105+
* Describes the relationship between the embedded file.
106+
* - `Source`: The embedded file is the source material.
107+
* - `Data`: The embedded file contains data related to the document.
108+
* - `Alternative`: The embedded file is an alternative representation.
109+
* - `Supplement`: The embedded file supplements the document.
110+
* - `EncryptedPayload`: The embedded file is an encrypted payload.
111+
* - `FormData`: The embedded file contains form data.
112+
* - `Schema`: The embedded file contains a schema.
113+
* - `Unspecified`: No specific relationship.
114+
*/
115+
export type FileRelationShip =
116+
| 'Source'
117+
| 'Data'
118+
| 'Alternative'
119+
| 'Supplement'
120+
| 'EncryptedPayload'
121+
| 'FormData'
122+
| 'Schema'
123+
| 'Unspecified';
124+
104125
export type EmbeddedFile = {
105126
/**
106127
* The binary content of the file.
@@ -133,6 +154,11 @@ export type EmbeddedFile = {
133154
* The date and time when the file was last modified.
134155
*/
135156
modificationDate?: Date;
157+
158+
/**
159+
* The relationship between the file and the PDF document.
160+
*/
161+
relationship?: FileRelationShip;
136162
};
137163

138164
/**

src/read-document.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { PDFDocument } from 'pdf-lib';
22

3+
import type { FileRelationShip } from './api/document.ts';
34
import type { BoxEdges, Size } from './box.ts';
45
import { parseEdges } from './box.ts';
56
import type { FontDef } from './fonts.ts';
@@ -32,6 +33,7 @@ export type DocumentDefinition = {
3233
description?: string;
3334
creationDate?: Date;
3435
modificationDate?: Date;
36+
relationship?: FileRelationShip;
3537
}[];
3638
onRenderDocument?: (pdfDoc: PDFDocument) => void;
3739
};
@@ -106,15 +108,33 @@ function readCustomData(input: unknown) {
106108
);
107109
}
108110

111+
/**
112+
* From the PDF-A3 specification, section **3.1. Requirements -
113+
* General**. See:
114+
* https://www.pdfa.org/wp-content/uploads/2018/10/PDF20_AN002-AF.pdf
115+
*/
116+
const readFileRelationship = types.string({
117+
enum: [
118+
'Source',
119+
'Data',
120+
'Alternative',
121+
'Supplement',
122+
'EncryptedPayload',
123+
'FormData',
124+
'Schema',
125+
'Unspecified',
126+
],
127+
});
128+
109129
function readEmbeddedFiles(input: unknown) {
110130
return readObject(input, {
111-
url: optional(types.string()),
112131
content: required(readData),
113132
fileName: required(types.string()),
114133
mimeType: required(types.string()),
115134
description: optional(types.string()),
116135
creationDate: optional(types.date()),
117136
modificationDate: optional(types.date()),
137+
relationship: optional(readFileRelationship),
118138
});
119139
}
120140

src/render/render-document.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { PDFDict } from 'pdf-lib';
1+
import type { AFRelationship, PDFDict } from 'pdf-lib';
22
import { PDFDocument, PDFHexString, PDFName } from 'pdf-lib';
33

44
import type { Page } from '../page.ts';
@@ -19,6 +19,7 @@ export async function renderDocument(def: DocumentDefinition, pages: Page[]): Pr
1919
description: file.description,
2020
creationDate: file.creationDate,
2121
modificationDate: file.modificationDate,
22+
afRelationship: file.relationship as AFRelationship | undefined,
2223
});
2324
}
2425

0 commit comments

Comments
 (0)