@aglyn/aglyn 1.0.0-beta.197 → 1.0.0-beta.199
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.
- package/package.json +11 -11
- package/src/lib/app-utils/docs-help.generated.d.ts +1 -1
- package/src/lib/app-utils/docs-help.generated.js +1 -0
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +3 -3
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/media-embedded-fields.d.ts +471 -0
- package/src/lib/app-utils/media-embedded-fields.js +619 -0
- package/src/lib/app-utils/media-embedded-fields.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.d.ts +160 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.js +1267 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.d.ts +44 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.js +134 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.d.ts +23 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.js +354 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.d.ts +22 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.js +85 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.d.ts +145 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.js +200 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/index.d.ts +93 -0
- package/src/lib/app-utils/media-embedded-metadata/index.js +744 -0
- package/src/lib/app-utils/media-embedded-metadata/index.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.d.ts +59 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.js +529 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.d.ts +43 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.js +456 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.d.ts +37 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.js +621 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.d.ts +131 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.js +1058 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.d.ts +223 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.js +936 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.d.ts +82 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.js +1167 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/png.d.ts +41 -0
- package/src/lib/app-utils/media-embedded-metadata/png.js +512 -0
- package/src/lib/app-utils/media-embedded-metadata/png.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.d.ts +30 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.js +154 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.d.ts +40 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.js +158 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/types.d.ts +60 -0
- package/src/lib/app-utils/media-embedded-metadata/types.js +32 -0
- package/src/lib/app-utils/media-embedded-metadata/types.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.d.ts +26 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.js +417 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.d.ts +37 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.js +272 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.d.ts +231 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.js +598 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.d.ts +100 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.js +1475 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.d.ts +93 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.js +531 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.js.map +1 -0
- package/src/lib/app-utils/name-search.d.ts +12 -0
- package/src/lib/app-utils/name-search.js +11 -0
- package/src/lib/app-utils/name-search.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +11 -0
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/server.d.ts +1 -0
- package/src/server.js +7 -0
- package/src/server.js.map +1 -1
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The metadata a file carries INSIDE its own bytes (AGL-3331): EXIF, IPTC
|
|
19
|
+
* and XMP on a photo, the document info of a PDF, the core and custom
|
|
20
|
+
* properties of an Office file, the tags of a video container.
|
|
21
|
+
*
|
|
22
|
+
* ## Why this module is client-safe and the parsers are not
|
|
23
|
+
*
|
|
24
|
+
* The parsers and writers live in `media-embedded-metadata/` and are exposed
|
|
25
|
+
* only through `@aglyn/aglyn/server` — they need `node:zlib` and
|
|
26
|
+
* `node:crypto`, and nothing in a browser ever holds the bytes they read.
|
|
27
|
+
* What the console needs is the SHAPE of what they produced (it is stored on
|
|
28
|
+
* the media document) and the rules for presenting and editing it, which is
|
|
29
|
+
* everything here. Keeping the two apart keeps a PDF parser out of the
|
|
30
|
+
* console bundle.
|
|
31
|
+
*
|
|
32
|
+
* ## Canonical keys
|
|
33
|
+
*
|
|
34
|
+
* A photo's caption can be written in three places at once — XMP
|
|
35
|
+
* `dc:description`, IPTC 2:120 and EXIF `ImageDescription` — and a PDF's in
|
|
36
|
+
* two. The reader folds every spelling of one idea into one canonical key
|
|
37
|
+
* ({@link MEDIA_EMBEDDED_CATALOG}), so the drawer shows ONE "Description"
|
|
38
|
+
* rather than three rows that may or may not agree, and the writer fans an
|
|
39
|
+
* edit back out to every place that already holds it (the Metadata Working
|
|
40
|
+
* Group's rule: never leave a stale copy for the next reader to prefer).
|
|
41
|
+
*
|
|
42
|
+
* Anything a file carries that is not in the catalog — an XMP property from
|
|
43
|
+
* a DAM we have never heard of, a PDF custom property, a PNG text chunk —
|
|
44
|
+
* still surfaces, under a namespaced "other" key ({@link otherEmbeddedKey})
|
|
45
|
+
* that round-trips to the writer unchanged.
|
|
46
|
+
*/
|
|
47
|
+
/** Where a value was read from. Several sources can back one field. */
|
|
48
|
+
export type MediaEmbeddedSource = 'xmp' | 'iptc' | 'exif' | 'icc' | 'png' | 'comment' | 'pdf' | 'ooxml' | 'mp4' | 'webm' | 'svg';
|
|
49
|
+
/** How the drawer groups fields, in display order. */
|
|
50
|
+
export type MediaEmbeddedGroup = 'description' | 'rights' | 'location' | 'capture' | 'document' | 'technical' | 'other';
|
|
51
|
+
export declare const MEDIA_EMBEDDED_GROUP_ORDER: readonly MediaEmbeddedGroup[];
|
|
52
|
+
export declare const MEDIA_EMBEDDED_GROUP_LABELS: Record<MediaEmbeddedGroup, string>;
|
|
53
|
+
/**
|
|
54
|
+
* The container a file was read as. `null`-free: a file whose format has no
|
|
55
|
+
* reader is simply not given an `embeddedMetadata` record at all.
|
|
56
|
+
*/
|
|
57
|
+
export type MediaEmbeddedFormat = 'jpeg' | 'png' | 'webp' | 'gif' | 'tiff' | 'heif' | 'svg' | 'pdf' | 'ooxml' | 'mp4' | 'webm';
|
|
58
|
+
/**
|
|
59
|
+
* The formats whose bytes can take an edit without being re-encoded.
|
|
60
|
+
*
|
|
61
|
+
* Every writer here rewrites METADATA containers only — JPEG APP segments,
|
|
62
|
+
* PNG ancillary chunks, WebP RIFF chunks, a TIFF's IFD, a PDF incremental
|
|
63
|
+
* update, an Office package's property parts — and copies the image data,
|
|
64
|
+
* page content and every other part through byte for byte. A format that
|
|
65
|
+
* cannot promise that (a video's `moov` would move its sample offsets; an
|
|
66
|
+
* SVG is sanitized on every ingress and is its own markup) is read-only.
|
|
67
|
+
*/
|
|
68
|
+
export declare const MEDIA_EMBEDDED_WRITABLE_FORMATS: ReadonlySet<MediaEmbeddedFormat>;
|
|
69
|
+
/** How a value is typed, which decides the editor and the validation. */
|
|
70
|
+
export type MediaEmbeddedValueKind = 'text' | 'longText' | 'list' | 'date' | 'rating' | 'gps';
|
|
71
|
+
export interface MediaEmbeddedCatalogEntry {
|
|
72
|
+
label: string;
|
|
73
|
+
group: MediaEmbeddedGroup;
|
|
74
|
+
kind: MediaEmbeddedValueKind;
|
|
75
|
+
/**
|
|
76
|
+
* The formats an edit of this key can be written into. Absent means the
|
|
77
|
+
* key is read-only everywhere — a measured fact such as an exposure time
|
|
78
|
+
* or a page count, which describes the bytes rather than annotating them.
|
|
79
|
+
*/
|
|
80
|
+
writable?: readonly MediaEmbeddedFormat[];
|
|
81
|
+
/**
|
|
82
|
+
* `gps` only: the one edit offered is removal. Moving a photo's recorded
|
|
83
|
+
* location is not a thing anybody needs from a DAM; taking it OFF a photo
|
|
84
|
+
* before it goes on a public page is.
|
|
85
|
+
*/
|
|
86
|
+
removeOnly?: boolean;
|
|
87
|
+
/** Format-specific label, where a format names the idea differently. */
|
|
88
|
+
labels?: Partial<Record<MediaEmbeddedFormat, string>>;
|
|
89
|
+
/** Format-specific group — a PDF's creation date is not a camera fact. */
|
|
90
|
+
groups?: Partial<Record<MediaEmbeddedFormat, MediaEmbeddedGroup>>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Every canonical key, in display order within its group.
|
|
94
|
+
*
|
|
95
|
+
* ## Value formats every reader and writer agrees on
|
|
96
|
+
*
|
|
97
|
+
* - `date`: ISO 8601 — `2021-05-03T10:11:12`, with `Z` or `±HH:MM` only when
|
|
98
|
+
* the source recorded a zone (EXIF 2.3's `OffsetTimeOriginal`, a PDF
|
|
99
|
+
* date's `+05'00'`). Never invented: a local camera time stays local.
|
|
100
|
+
* - `list`: an array of strings (creators, keywords).
|
|
101
|
+
* - `gps`: `"<lat>,<lon>"` in signed decimal degrees, six places.
|
|
102
|
+
* - `rating`: `"0"`–`"5"`, XMP's scale; `"-1"` is XMP's "rejected".
|
|
103
|
+
* - technical values are display strings already (`1/250`, `f/2.8`,
|
|
104
|
+
* `35 mm`) because nothing edits them.
|
|
105
|
+
*/
|
|
106
|
+
export declare const MEDIA_EMBEDDED_CATALOG: {
|
|
107
|
+
readonly title: {
|
|
108
|
+
readonly label: "Title";
|
|
109
|
+
readonly group: "description";
|
|
110
|
+
readonly kind: "text";
|
|
111
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
112
|
+
};
|
|
113
|
+
readonly headline: {
|
|
114
|
+
readonly label: "Headline";
|
|
115
|
+
readonly group: "description";
|
|
116
|
+
readonly kind: "text";
|
|
117
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
118
|
+
};
|
|
119
|
+
readonly description: {
|
|
120
|
+
readonly label: "Description";
|
|
121
|
+
readonly group: "description";
|
|
122
|
+
readonly kind: "longText";
|
|
123
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
124
|
+
readonly labels: {
|
|
125
|
+
readonly pdf: "Subject";
|
|
126
|
+
readonly ooxml: "Comments";
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
readonly subject: {
|
|
130
|
+
readonly label: "Subject";
|
|
131
|
+
readonly group: "description";
|
|
132
|
+
readonly kind: "text";
|
|
133
|
+
readonly writable: readonly ["ooxml"];
|
|
134
|
+
};
|
|
135
|
+
readonly keywords: {
|
|
136
|
+
readonly label: "Keywords";
|
|
137
|
+
readonly group: "description";
|
|
138
|
+
readonly kind: "list";
|
|
139
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
140
|
+
};
|
|
141
|
+
readonly category: {
|
|
142
|
+
readonly label: "Category";
|
|
143
|
+
readonly group: "description";
|
|
144
|
+
readonly kind: "text";
|
|
145
|
+
readonly writable: readonly ["ooxml"];
|
|
146
|
+
};
|
|
147
|
+
readonly comment: {
|
|
148
|
+
readonly label: "Comment";
|
|
149
|
+
readonly group: "description";
|
|
150
|
+
readonly kind: "longText";
|
|
151
|
+
readonly writable: readonly ["png"];
|
|
152
|
+
};
|
|
153
|
+
readonly instructions: {
|
|
154
|
+
readonly label: "Instructions";
|
|
155
|
+
readonly group: "description";
|
|
156
|
+
readonly kind: "longText";
|
|
157
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
158
|
+
};
|
|
159
|
+
readonly label: {
|
|
160
|
+
readonly label: "Label";
|
|
161
|
+
readonly group: "description";
|
|
162
|
+
readonly kind: "text";
|
|
163
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
164
|
+
};
|
|
165
|
+
readonly rating: {
|
|
166
|
+
readonly label: "Rating";
|
|
167
|
+
readonly group: "description";
|
|
168
|
+
readonly kind: "rating";
|
|
169
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
170
|
+
};
|
|
171
|
+
readonly creator: {
|
|
172
|
+
readonly label: "Creator";
|
|
173
|
+
readonly group: "rights";
|
|
174
|
+
readonly kind: "list";
|
|
175
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
176
|
+
readonly labels: {
|
|
177
|
+
readonly pdf: "Author";
|
|
178
|
+
readonly ooxml: "Author";
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
readonly copyright: {
|
|
182
|
+
readonly label: "Copyright";
|
|
183
|
+
readonly group: "rights";
|
|
184
|
+
readonly kind: "text";
|
|
185
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
186
|
+
};
|
|
187
|
+
readonly credit: {
|
|
188
|
+
readonly label: "Credit line";
|
|
189
|
+
readonly group: "rights";
|
|
190
|
+
readonly kind: "text";
|
|
191
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
192
|
+
};
|
|
193
|
+
readonly source: {
|
|
194
|
+
readonly label: "Source";
|
|
195
|
+
readonly group: "rights";
|
|
196
|
+
readonly kind: "text";
|
|
197
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
198
|
+
};
|
|
199
|
+
readonly usageTerms: {
|
|
200
|
+
readonly label: "Usage terms";
|
|
201
|
+
readonly group: "rights";
|
|
202
|
+
readonly kind: "longText";
|
|
203
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
204
|
+
};
|
|
205
|
+
readonly webStatement: {
|
|
206
|
+
readonly label: "Copyright info URL";
|
|
207
|
+
readonly group: "rights";
|
|
208
|
+
readonly kind: "text";
|
|
209
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
210
|
+
};
|
|
211
|
+
readonly city: {
|
|
212
|
+
readonly label: "City";
|
|
213
|
+
readonly group: "location";
|
|
214
|
+
readonly kind: "text";
|
|
215
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
216
|
+
};
|
|
217
|
+
readonly state: {
|
|
218
|
+
readonly label: "State / province";
|
|
219
|
+
readonly group: "location";
|
|
220
|
+
readonly kind: "text";
|
|
221
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
222
|
+
};
|
|
223
|
+
readonly country: {
|
|
224
|
+
readonly label: "Country";
|
|
225
|
+
readonly group: "location";
|
|
226
|
+
readonly kind: "text";
|
|
227
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
228
|
+
};
|
|
229
|
+
readonly gps: {
|
|
230
|
+
readonly label: "GPS position";
|
|
231
|
+
readonly group: "location";
|
|
232
|
+
readonly kind: "gps";
|
|
233
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
234
|
+
readonly removeOnly: true;
|
|
235
|
+
};
|
|
236
|
+
readonly gpsAltitude: {
|
|
237
|
+
readonly label: "Altitude";
|
|
238
|
+
readonly group: "location";
|
|
239
|
+
readonly kind: "text";
|
|
240
|
+
};
|
|
241
|
+
readonly createdAt: {
|
|
242
|
+
readonly label: "Date taken";
|
|
243
|
+
readonly group: "capture";
|
|
244
|
+
readonly kind: "date";
|
|
245
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
246
|
+
readonly labels: {
|
|
247
|
+
readonly pdf: "Created";
|
|
248
|
+
readonly ooxml: "Created";
|
|
249
|
+
readonly svg: "Created";
|
|
250
|
+
readonly mp4: "Recorded";
|
|
251
|
+
readonly webm: "Recorded";
|
|
252
|
+
};
|
|
253
|
+
readonly groups: {
|
|
254
|
+
readonly pdf: "document";
|
|
255
|
+
readonly ooxml: "document";
|
|
256
|
+
readonly svg: "document";
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
readonly make: {
|
|
260
|
+
readonly label: "Camera make";
|
|
261
|
+
readonly group: "capture";
|
|
262
|
+
readonly kind: "text";
|
|
263
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
264
|
+
};
|
|
265
|
+
readonly model: {
|
|
266
|
+
readonly label: "Camera model";
|
|
267
|
+
readonly group: "capture";
|
|
268
|
+
readonly kind: "text";
|
|
269
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
270
|
+
};
|
|
271
|
+
readonly lens: {
|
|
272
|
+
readonly label: "Lens";
|
|
273
|
+
readonly group: "capture";
|
|
274
|
+
readonly kind: "text";
|
|
275
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
276
|
+
};
|
|
277
|
+
readonly exposure: {
|
|
278
|
+
readonly label: "Exposure";
|
|
279
|
+
readonly group: "capture";
|
|
280
|
+
readonly kind: "text";
|
|
281
|
+
};
|
|
282
|
+
readonly aperture: {
|
|
283
|
+
readonly label: "Aperture";
|
|
284
|
+
readonly group: "capture";
|
|
285
|
+
readonly kind: "text";
|
|
286
|
+
};
|
|
287
|
+
readonly iso: {
|
|
288
|
+
readonly label: "ISO";
|
|
289
|
+
readonly group: "capture";
|
|
290
|
+
readonly kind: "text";
|
|
291
|
+
};
|
|
292
|
+
readonly focalLength: {
|
|
293
|
+
readonly label: "Focal length";
|
|
294
|
+
readonly group: "capture";
|
|
295
|
+
readonly kind: "text";
|
|
296
|
+
};
|
|
297
|
+
readonly flash: {
|
|
298
|
+
readonly label: "Flash";
|
|
299
|
+
readonly group: "capture";
|
|
300
|
+
readonly kind: "text";
|
|
301
|
+
};
|
|
302
|
+
readonly modifiedAt: {
|
|
303
|
+
readonly label: "Modified";
|
|
304
|
+
readonly group: "document";
|
|
305
|
+
readonly kind: "date";
|
|
306
|
+
};
|
|
307
|
+
readonly software: {
|
|
308
|
+
readonly label: "Software";
|
|
309
|
+
readonly group: "document";
|
|
310
|
+
readonly kind: "text";
|
|
311
|
+
readonly writable: readonly MediaEmbeddedFormat[];
|
|
312
|
+
readonly labels: {
|
|
313
|
+
readonly pdf: "Created with";
|
|
314
|
+
readonly ooxml: "Application";
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
readonly producer: {
|
|
318
|
+
readonly label: "PDF producer";
|
|
319
|
+
readonly group: "document";
|
|
320
|
+
readonly kind: "text";
|
|
321
|
+
readonly writable: readonly ["pdf"];
|
|
322
|
+
};
|
|
323
|
+
readonly lastModifiedBy: {
|
|
324
|
+
readonly label: "Last modified by";
|
|
325
|
+
readonly group: "document";
|
|
326
|
+
readonly kind: "text";
|
|
327
|
+
};
|
|
328
|
+
readonly company: {
|
|
329
|
+
readonly label: "Company";
|
|
330
|
+
readonly group: "document";
|
|
331
|
+
readonly kind: "text";
|
|
332
|
+
};
|
|
333
|
+
readonly pageCount: {
|
|
334
|
+
readonly label: "Pages";
|
|
335
|
+
readonly group: "document";
|
|
336
|
+
readonly kind: "text";
|
|
337
|
+
readonly labels: {
|
|
338
|
+
readonly ooxml: "Pages / slides";
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
readonly pdfVersion: {
|
|
342
|
+
readonly label: "PDF version";
|
|
343
|
+
readonly group: "document";
|
|
344
|
+
readonly kind: "text";
|
|
345
|
+
};
|
|
346
|
+
readonly orientation: {
|
|
347
|
+
readonly label: "Orientation";
|
|
348
|
+
readonly group: "technical";
|
|
349
|
+
readonly kind: "text";
|
|
350
|
+
};
|
|
351
|
+
readonly colorProfile: {
|
|
352
|
+
readonly label: "Color profile";
|
|
353
|
+
readonly group: "technical";
|
|
354
|
+
readonly kind: "text";
|
|
355
|
+
};
|
|
356
|
+
readonly encoder: {
|
|
357
|
+
readonly label: "Encoder";
|
|
358
|
+
readonly group: "technical";
|
|
359
|
+
readonly kind: "text";
|
|
360
|
+
};
|
|
361
|
+
};
|
|
362
|
+
export type MediaEmbeddedCanonicalKey = keyof typeof MEDIA_EMBEDDED_CATALOG;
|
|
363
|
+
/**
|
|
364
|
+
* The namespaces an "other" key can come from. The key round-trips from
|
|
365
|
+
* reader to writer verbatim, so its only job is to be unambiguous:
|
|
366
|
+
*
|
|
367
|
+
* - `xmp|<namespace URI>|<local name>` — a simple XMP property outside the
|
|
368
|
+
* catalog. Keyed by URI, not prefix, because two files may bind the same
|
|
369
|
+
* namespace to different prefixes and must still produce one key.
|
|
370
|
+
* - `png|<keyword>` — a PNG `tEXt`/`zTXt`/`iTXt` chunk.
|
|
371
|
+
* - `pdf|<Name>` — a PDF document-info entry (Acrobat's "Custom" tab).
|
|
372
|
+
* - `ooxml|<name>` — an Office custom document property.
|
|
373
|
+
* - `mp4|<atom or freeform name>`, `webm|<TAG>` — video tags, read-only.
|
|
374
|
+
*/
|
|
375
|
+
export type MediaEmbeddedOtherNamespace = 'xmp' | 'png' | 'pdf' | 'ooxml' | 'mp4' | 'webm';
|
|
376
|
+
export declare function otherEmbeddedKey(namespace: MediaEmbeddedOtherNamespace, ...parts: string[]): string;
|
|
377
|
+
export declare function parseOtherEmbeddedKey(key: string): {
|
|
378
|
+
namespace: MediaEmbeddedOtherNamespace;
|
|
379
|
+
parts: string[];
|
|
380
|
+
} | null;
|
|
381
|
+
/** One field as stored on the media document and shown in the drawer. */
|
|
382
|
+
export interface MediaEmbeddedField {
|
|
383
|
+
/** A {@link MediaEmbeddedCanonicalKey} or an {@link otherEmbeddedKey}. */
|
|
384
|
+
key: string;
|
|
385
|
+
label: string;
|
|
386
|
+
group: MediaEmbeddedGroup;
|
|
387
|
+
/** Single-valued fields. Absent when `values` is set. */
|
|
388
|
+
value?: string;
|
|
389
|
+
/** List-valued fields (creators, keywords). */
|
|
390
|
+
values?: string[];
|
|
391
|
+
/** Every block the value was found in, strongest first. */
|
|
392
|
+
sources: MediaEmbeddedSource[];
|
|
393
|
+
/** Whether the drawer may offer an edit for it on this file. */
|
|
394
|
+
editable: boolean;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* `embeddedMetadata` on a media document (AGL-3331). Server-written only —
|
|
398
|
+
* the Firestore rules lock it like every other fact read from the bytes.
|
|
399
|
+
*/
|
|
400
|
+
export interface MediaEmbeddedMetadata {
|
|
401
|
+
/** Bumped when the reader's output changes shape, so a sweep can re-read. */
|
|
402
|
+
version: number;
|
|
403
|
+
format: MediaEmbeddedFormat;
|
|
404
|
+
fields: MediaEmbeddedField[];
|
|
405
|
+
/** Whether an edit can be written back into this file at all. */
|
|
406
|
+
writable: boolean;
|
|
407
|
+
/** Why not, in a sentence for the drawer, when `writable` is false. */
|
|
408
|
+
readOnlyReason?: string;
|
|
409
|
+
/** True when fields were dropped to stay inside the stored caps. */
|
|
410
|
+
truncated?: boolean;
|
|
411
|
+
/**
|
|
412
|
+
* The `contentSha256` of the bytes this was read from. A record whose
|
|
413
|
+
* digest no longer matches the document's is stale — the file was
|
|
414
|
+
* replaced by a path that did not re-read it — and is re-read on open.
|
|
415
|
+
*/
|
|
416
|
+
contentSha256?: string;
|
|
417
|
+
}
|
|
418
|
+
/** The reader's output version. See {@link MediaEmbeddedMetadata.version}. */
|
|
419
|
+
export declare const MEDIA_EMBEDDED_METADATA_VERSION = 1;
|
|
420
|
+
/** Stored caps: one media document must never approach Firestore's 1 MiB. */
|
|
421
|
+
export declare const MEDIA_EMBEDDED_MAX_FIELDS = 150;
|
|
422
|
+
export declare const MEDIA_EMBEDDED_MAX_VALUE_LENGTH = 2000;
|
|
423
|
+
export declare const MEDIA_EMBEDDED_MAX_LIST_ITEMS = 100;
|
|
424
|
+
/** A single keyword or creator; IPTC's own limit for keywords is 64 bytes. */
|
|
425
|
+
export declare const MEDIA_EMBEDDED_MAX_LIST_ITEM_LENGTH = 256;
|
|
426
|
+
/**
|
|
427
|
+
* An edit to a file's embedded metadata: key → new value, or `null` to
|
|
428
|
+
* remove it from the file. A list-valued key takes an array.
|
|
429
|
+
*/
|
|
430
|
+
export type MediaEmbeddedPatch = Record<string, string | string[] | null>;
|
|
431
|
+
export declare function isCanonicalEmbeddedKey(key: string): key is MediaEmbeddedCanonicalKey;
|
|
432
|
+
/** The label a key carries on a given format. */
|
|
433
|
+
export declare function embeddedFieldLabel(key: string, format: MediaEmbeddedFormat, fallback?: string): string;
|
|
434
|
+
/** The group a key is shown under on a given format. */
|
|
435
|
+
export declare function embeddedFieldGroup(key: string, format: MediaEmbeddedFormat): MediaEmbeddedGroup;
|
|
436
|
+
/** How a key's value is edited. Other keys are free text. */
|
|
437
|
+
export declare function embeddedFieldKind(key: string): MediaEmbeddedValueKind;
|
|
438
|
+
/**
|
|
439
|
+
* Whether an edit of `key` can be written into a file of `format`.
|
|
440
|
+
*
|
|
441
|
+
* The one place the answer lives: the reader stamps `editable` with it, the
|
|
442
|
+
* drawer offers the "add a field" choices from it, and the write route
|
|
443
|
+
* refuses anything it says no to — so the three cannot disagree about which
|
|
444
|
+
* fields a JPEG can take.
|
|
445
|
+
*/
|
|
446
|
+
export declare function embeddedKeyWritable(key: string, format: MediaEmbeddedFormat): boolean;
|
|
447
|
+
/**
|
|
448
|
+
* The canonical keys a file of this format can take, whether or not it
|
|
449
|
+
* holds them yet — what the drawer offers under "Add a field".
|
|
450
|
+
*/
|
|
451
|
+
export declare function embeddedWritableKeys(format: MediaEmbeddedFormat): MediaEmbeddedCanonicalKey[];
|
|
452
|
+
/**
|
|
453
|
+
* Validate an edit before it reaches a writer, or say why it cannot.
|
|
454
|
+
*
|
|
455
|
+
* Runs in the drawer (to explain) and in the write route (to refuse), so
|
|
456
|
+
* the messages are written for the person who typed the value.
|
|
457
|
+
*/
|
|
458
|
+
export declare function sanitizeEmbeddedPatch(format: MediaEmbeddedFormat, patch: unknown): {
|
|
459
|
+
patch: MediaEmbeddedPatch;
|
|
460
|
+
} | {
|
|
461
|
+
error: string;
|
|
462
|
+
};
|
|
463
|
+
/** The value of a field as one line of text. */
|
|
464
|
+
export declare function embeddedFieldText(field: MediaEmbeddedField): string;
|
|
465
|
+
export declare function embeddedMetadataReadable(contentType: unknown): boolean;
|
|
466
|
+
/**
|
|
467
|
+
* A field's value as the drawer shows it — the stored value is the
|
|
468
|
+
* machine form every writer agrees on, and this is the only place it is
|
|
469
|
+
* dressed for a person.
|
|
470
|
+
*/
|
|
471
|
+
export declare function embeddedFieldDisplay(field: Pick<MediaEmbeddedField, 'key' | 'value' | 'values'>, locale?: string): string;
|