@aglyn/aglyn 1.0.0-beta.198 → 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-index.generated.js +1 -1
- 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,145 @@
|
|
|
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 raw metadata BLOCKS of an image container (AGL-3331), and the byte
|
|
19
|
+
* helpers the container modules share.
|
|
20
|
+
*
|
|
21
|
+
* Each image format hides the same few payloads in its own wrapper — EXIF is
|
|
22
|
+
* a JPEG APP1 segment, a PNG `eXIf` chunk, a WebP `EXIF` chunk and a HEIF
|
|
23
|
+
* item — and the container modules (`jpeg.ts`, `png.ts`, `webp.ts`, `gif.ts`,
|
|
24
|
+
* `heif.ts`) do nothing but find those payloads and, for the writable
|
|
25
|
+
* formats, put new ones back. They never interpret EXIF, IPTC or XMP; the
|
|
26
|
+
* block readers do, over the {@link ImageBlocks} handed to them. Keeping the
|
|
27
|
+
* split is what lets one EXIF parser serve four containers.
|
|
28
|
+
*/
|
|
29
|
+
/** One PNG text chunk (PNG 3rd edition, 11.3.3). */
|
|
30
|
+
export interface PngTextChunk {
|
|
31
|
+
/** 1 to 79 Latin-1 characters. */
|
|
32
|
+
keyword: string;
|
|
33
|
+
text: string;
|
|
34
|
+
type: 'tEXt' | 'zTXt' | 'iTXt';
|
|
35
|
+
/** `iTXt` only: the RFC 3066 language tag, when there is one. */
|
|
36
|
+
language?: string;
|
|
37
|
+
/** `iTXt` only: the keyword translated into `language`. */
|
|
38
|
+
translatedKeyword?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The metadata payloads found in one image, unwrapped from their container.
|
|
42
|
+
* A key is absent when the file does not carry that block.
|
|
43
|
+
*/
|
|
44
|
+
export interface ImageBlocks {
|
|
45
|
+
/**
|
|
46
|
+
* TIFF-structured EXIF, starting at the byte-order mark (`II*\0` or
|
|
47
|
+
* `MM\0*`): the JPEG `Exif\0\0` prefix and HEIF's 4-byte header offset are
|
|
48
|
+
* already stripped.
|
|
49
|
+
*/
|
|
50
|
+
exif?: Uint8Array;
|
|
51
|
+
/** The standard (main) XMP packet, decoded as UTF-8. */
|
|
52
|
+
xmp?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Photoshop Image Resource Blocks — the JPEG APP13 payload after
|
|
55
|
+
* `Photoshop 3.0\0`, with several consecutive APP13 segments concatenated
|
|
56
|
+
* in file order the way Photoshop splits a large one.
|
|
57
|
+
*/
|
|
58
|
+
irb?: Uint8Array;
|
|
59
|
+
/** JPEG COM segments and GIF comment extensions, in file order. */
|
|
60
|
+
comments?: string[];
|
|
61
|
+
/** Every PNG text chunk except the XMP one, in file order. */
|
|
62
|
+
pngText?: PngTextChunk[];
|
|
63
|
+
/**
|
|
64
|
+
* The ICC profile: JPEG APP2 `ICC_PROFILE` chunks reassembled by sequence
|
|
65
|
+
* number, a PNG `iCCP` inflated, a WebP `ICCP`, a GIF `ICCRGBG1`
|
|
66
|
+
* application extension, or a HEIF `colr` box of type `prof`/`rICC`.
|
|
67
|
+
*/
|
|
68
|
+
icc?: Uint8Array;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* An edit to an image's blocks. For every key, `undefined` keeps the block
|
|
72
|
+
* as it is and `null` removes it.
|
|
73
|
+
*
|
|
74
|
+
* A writer throws `EmbeddedWriteError` when asked to SET a block its
|
|
75
|
+
* container has no place for (IRB in a PNG, a text chunk in a JPEG); asking
|
|
76
|
+
* to remove one is a no-op, since the file already does not carry it.
|
|
77
|
+
*/
|
|
78
|
+
export interface ImageBlockUpdate {
|
|
79
|
+
exif?: Uint8Array | null;
|
|
80
|
+
xmp?: string | null;
|
|
81
|
+
irb?: Uint8Array | null;
|
|
82
|
+
/** PNG only: set or remove a text chunk by keyword. */
|
|
83
|
+
pngText?: Record<string, string | null>;
|
|
84
|
+
}
|
|
85
|
+
/** Reads an unsigned 16-bit big-endian integer. */
|
|
86
|
+
export declare function readU16BE(bytes: Uint8Array, offset: number): number;
|
|
87
|
+
/** Reads an unsigned 16-bit little-endian integer. */
|
|
88
|
+
export declare function readU16LE(bytes: Uint8Array, offset: number): number;
|
|
89
|
+
/** Reads an unsigned 24-bit little-endian integer. */
|
|
90
|
+
export declare function readU24LE(bytes: Uint8Array, offset: number): number;
|
|
91
|
+
/** Reads an unsigned 32-bit big-endian integer. */
|
|
92
|
+
export declare function readU32BE(bytes: Uint8Array, offset: number): number;
|
|
93
|
+
/** Reads an unsigned 32-bit little-endian integer. */
|
|
94
|
+
export declare function readU32LE(bytes: Uint8Array, offset: number): number;
|
|
95
|
+
/** Writes an unsigned 16-bit big-endian integer. */
|
|
96
|
+
export declare function writeU16BE(bytes: Uint8Array, offset: number, value: number): void;
|
|
97
|
+
/** Writes an unsigned 32-bit big-endian integer. */
|
|
98
|
+
export declare function writeU32BE(bytes: Uint8Array, offset: number, value: number): void;
|
|
99
|
+
/** Writes an unsigned 32-bit little-endian integer. */
|
|
100
|
+
export declare function writeU32LE(bytes: Uint8Array, offset: number, value: number): void;
|
|
101
|
+
/** Whether `bytes` holds exactly `magic` at `offset`. */
|
|
102
|
+
export declare function bytesAt(bytes: Uint8Array, offset: number, magic: Uint8Array): boolean;
|
|
103
|
+
/** The first index of `needle` in `bytes` at or after `from`, or -1. */
|
|
104
|
+
export declare function indexOfBytes(bytes: Uint8Array, needle: Uint8Array, from?: number, to?: number): number;
|
|
105
|
+
/** The ASCII (Latin-1) bytes of a string of code points below 256. */
|
|
106
|
+
export declare function asciiBytes(text: string): Uint8Array;
|
|
107
|
+
/** Reads `length` bytes at `offset` as a four-character code or tag. */
|
|
108
|
+
export declare function readAscii(bytes: Uint8Array, offset: number, length: number): string;
|
|
109
|
+
/** Decodes ISO 8859-1, where every byte is the code point of its value. */
|
|
110
|
+
export declare function latin1Decode(bytes: Uint8Array): string;
|
|
111
|
+
/**
|
|
112
|
+
* Encodes a string as ISO 8859-1, or `null` when any character is outside
|
|
113
|
+
* it (the signal for PNG to use `iTXt` instead of `tEXt`).
|
|
114
|
+
*/
|
|
115
|
+
export declare function latin1Encode(text: string): Uint8Array | null;
|
|
116
|
+
/** Decodes UTF-8, replacing malformed sequences rather than throwing. */
|
|
117
|
+
export declare function utf8Decode(bytes: Uint8Array): string;
|
|
118
|
+
/** Encodes a string as UTF-8. */
|
|
119
|
+
export declare function utf8Encode(text: string): Uint8Array;
|
|
120
|
+
/**
|
|
121
|
+
* Decodes free text of unknown encoding — a JPEG COM segment, a GIF comment
|
|
122
|
+
* — as UTF-8 when it is valid UTF-8 and as Latin-1 otherwise. Neither format
|
|
123
|
+
* names an encoding; UTF-8 is what current tools write and Latin-1 is what
|
|
124
|
+
* older ones did, and a Latin-1 accent is almost never valid UTF-8.
|
|
125
|
+
*/
|
|
126
|
+
export declare function decodeFreeText(bytes: Uint8Array): string;
|
|
127
|
+
/** Decodes big-endian UTF-16 code units (ICC `mluc`/`desc` text). */
|
|
128
|
+
export declare function utf16beDecode(bytes: Uint8Array): string;
|
|
129
|
+
/** Removes trailing NUL characters, which several writers terminate with. */
|
|
130
|
+
export declare function trimNul(text: string): string;
|
|
131
|
+
/** Concatenates byte arrays into one new array. */
|
|
132
|
+
export declare function concatBytes(parts: readonly Uint8Array[]): Uint8Array;
|
|
133
|
+
/**
|
|
134
|
+
* CRC-32 (ISO 3309 / ITU-T V.42, polynomial 0xEDB88320), the checksum every
|
|
135
|
+
* PNG chunk ends with (PNG 3rd edition, 5.5). Computed here rather than
|
|
136
|
+
* through `zlib.crc32`, which older Node releases do not have.
|
|
137
|
+
*/
|
|
138
|
+
export declare function crc32(...parts: Uint8Array[]): number;
|
|
139
|
+
/**
|
|
140
|
+
* The sentence every writer throws when a block will not fit its container
|
|
141
|
+
* — a JPEG segment tops out at 64 KB.
|
|
142
|
+
*/
|
|
143
|
+
export declare const METADATA_TOO_LARGE = "This file's embedded metadata is too large to edit here.";
|
|
144
|
+
/** The sentence a writer throws when the file's own structure is broken. */
|
|
145
|
+
export declare const FILE_DAMAGED = "This file's structure is damaged, so its embedded metadata cannot be edited safely.";
|
|
@@ -0,0 +1,200 @@
|
|
|
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
|
+
* The raw metadata BLOCKS of an image container (AGL-3331), and the byte
|
|
18
|
+
* helpers the container modules share.
|
|
19
|
+
*
|
|
20
|
+
* Each image format hides the same few payloads in its own wrapper — EXIF is
|
|
21
|
+
* a JPEG APP1 segment, a PNG `eXIf` chunk, a WebP `EXIF` chunk and a HEIF
|
|
22
|
+
* item — and the container modules (`jpeg.ts`, `png.ts`, `webp.ts`, `gif.ts`,
|
|
23
|
+
* `heif.ts`) do nothing but find those payloads and, for the writable
|
|
24
|
+
* formats, put new ones back. They never interpret EXIF, IPTC or XMP; the
|
|
25
|
+
* block readers do, over the {@link ImageBlocks} handed to them. Keeping the
|
|
26
|
+
* split is what lets one EXIF parser serve four containers.
|
|
27
|
+
*/ /** One PNG text chunk (PNG 3rd edition, 11.3.3). */ // ---------------------------------------------------------------------------
|
|
28
|
+
// Byte helpers shared by the container modules. Every read is bounds-safe: a
|
|
29
|
+
// byte past the end reads as 0, so a caller that checked its range once can
|
|
30
|
+
// read without a second check, and one that did not gets zeros, not a throw.
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/** Reads an unsigned 16-bit big-endian integer. */ export function readU16BE(bytes, offset) {
|
|
33
|
+
var _bytes_offset, _bytes_;
|
|
34
|
+
return ((_bytes_offset = bytes[offset]) != null ? _bytes_offset : 0) << 8 | ((_bytes_ = bytes[offset + 1]) != null ? _bytes_ : 0);
|
|
35
|
+
}
|
|
36
|
+
/** Reads an unsigned 16-bit little-endian integer. */ export function readU16LE(bytes, offset) {
|
|
37
|
+
var _bytes_offset, _bytes_;
|
|
38
|
+
return ((_bytes_offset = bytes[offset]) != null ? _bytes_offset : 0) | ((_bytes_ = bytes[offset + 1]) != null ? _bytes_ : 0) << 8;
|
|
39
|
+
}
|
|
40
|
+
/** Reads an unsigned 24-bit little-endian integer. */ export function readU24LE(bytes, offset) {
|
|
41
|
+
var _bytes_offset, _bytes_, _bytes_1;
|
|
42
|
+
return ((_bytes_offset = bytes[offset]) != null ? _bytes_offset : 0) | ((_bytes_ = bytes[offset + 1]) != null ? _bytes_ : 0) << 8 | ((_bytes_1 = bytes[offset + 2]) != null ? _bytes_1 : 0) << 16;
|
|
43
|
+
}
|
|
44
|
+
/** Reads an unsigned 32-bit big-endian integer. */ export function readU32BE(bytes, offset) {
|
|
45
|
+
var _bytes_offset, _bytes_, _bytes_1, _bytes_2;
|
|
46
|
+
return ((_bytes_offset = bytes[offset]) != null ? _bytes_offset : 0) * 0x1000000 + (((_bytes_ = bytes[offset + 1]) != null ? _bytes_ : 0) << 16 | ((_bytes_1 = bytes[offset + 2]) != null ? _bytes_1 : 0) << 8 | ((_bytes_2 = bytes[offset + 3]) != null ? _bytes_2 : 0));
|
|
47
|
+
}
|
|
48
|
+
/** Reads an unsigned 32-bit little-endian integer. */ export function readU32LE(bytes, offset) {
|
|
49
|
+
var _bytes_, _bytes_1, _bytes_2, _bytes_offset;
|
|
50
|
+
return ((_bytes_ = bytes[offset + 3]) != null ? _bytes_ : 0) * 0x1000000 + (((_bytes_1 = bytes[offset + 2]) != null ? _bytes_1 : 0) << 16 | ((_bytes_2 = bytes[offset + 1]) != null ? _bytes_2 : 0) << 8 | ((_bytes_offset = bytes[offset]) != null ? _bytes_offset : 0));
|
|
51
|
+
}
|
|
52
|
+
/** Writes an unsigned 16-bit big-endian integer. */ export function writeU16BE(bytes, offset, value) {
|
|
53
|
+
bytes[offset] = value >>> 8 & 0xff;
|
|
54
|
+
bytes[offset + 1] = value & 0xff;
|
|
55
|
+
}
|
|
56
|
+
/** Writes an unsigned 32-bit big-endian integer. */ export function writeU32BE(bytes, offset, value) {
|
|
57
|
+
bytes[offset] = value >>> 24 & 0xff;
|
|
58
|
+
bytes[offset + 1] = value >>> 16 & 0xff;
|
|
59
|
+
bytes[offset + 2] = value >>> 8 & 0xff;
|
|
60
|
+
bytes[offset + 3] = value & 0xff;
|
|
61
|
+
}
|
|
62
|
+
/** Writes an unsigned 32-bit little-endian integer. */ export function writeU32LE(bytes, offset, value) {
|
|
63
|
+
bytes[offset] = value & 0xff;
|
|
64
|
+
bytes[offset + 1] = value >>> 8 & 0xff;
|
|
65
|
+
bytes[offset + 2] = value >>> 16 & 0xff;
|
|
66
|
+
bytes[offset + 3] = value >>> 24 & 0xff;
|
|
67
|
+
}
|
|
68
|
+
/** Whether `bytes` holds exactly `magic` at `offset`. */ export function bytesAt(bytes, offset, magic) {
|
|
69
|
+
if (offset < 0 || offset + magic.length > bytes.length) return false;
|
|
70
|
+
for(let i = 0; i < magic.length; i += 1){
|
|
71
|
+
if (bytes[offset + i] !== magic[i]) return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
/** The first index of `needle` in `bytes` at or after `from`, or -1. */ export function indexOfBytes(bytes, needle, from = 0, to = bytes.length) {
|
|
76
|
+
const first = needle[0];
|
|
77
|
+
if (first === undefined) return -1;
|
|
78
|
+
const last = Math.min(to, bytes.length) - needle.length;
|
|
79
|
+
for(let i = Math.max(0, from); i <= last; i += 1){
|
|
80
|
+
if (bytes[i] === first && bytesAt(bytes, i, needle)) return i;
|
|
81
|
+
}
|
|
82
|
+
return -1;
|
|
83
|
+
}
|
|
84
|
+
/** The ASCII (Latin-1) bytes of a string of code points below 256. */ export function asciiBytes(text) {
|
|
85
|
+
const out = new Uint8Array(text.length);
|
|
86
|
+
for(let i = 0; i < text.length; i += 1)out[i] = text.charCodeAt(i) & 0xff;
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
/** Reads `length` bytes at `offset` as a four-character code or tag. */ export function readAscii(bytes, offset, length) {
|
|
90
|
+
let out = '';
|
|
91
|
+
const end = Math.min(bytes.length, offset + length);
|
|
92
|
+
for(let i = Math.max(0, offset); i < end; i += 1){
|
|
93
|
+
var _bytes_i;
|
|
94
|
+
out += String.fromCharCode((_bytes_i = bytes[i]) != null ? _bytes_i : 0);
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
/** Decodes ISO 8859-1, where every byte is the code point of its value. */ export function latin1Decode(bytes) {
|
|
99
|
+
let out = '';
|
|
100
|
+
// Chunked so a long text chunk never builds a huge argument list.
|
|
101
|
+
for(let i = 0; i < bytes.length; i += 0x2000){
|
|
102
|
+
out += String.fromCharCode(...bytes.subarray(i, i + 0x2000));
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Encodes a string as ISO 8859-1, or `null` when any character is outside
|
|
108
|
+
* it (the signal for PNG to use `iTXt` instead of `tEXt`).
|
|
109
|
+
*/ export function latin1Encode(text) {
|
|
110
|
+
const out = new Uint8Array(text.length);
|
|
111
|
+
for(let i = 0; i < text.length; i += 1){
|
|
112
|
+
const code = text.charCodeAt(i);
|
|
113
|
+
if (code > 0xff) return null;
|
|
114
|
+
out[i] = code;
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
const utf8Lenient = new TextDecoder('utf-8');
|
|
119
|
+
const utf8Strict = new TextDecoder('utf-8', {
|
|
120
|
+
fatal: true
|
|
121
|
+
});
|
|
122
|
+
const utf8Encoder = new TextEncoder();
|
|
123
|
+
/** Decodes UTF-8, replacing malformed sequences rather than throwing. */ export function utf8Decode(bytes) {
|
|
124
|
+
return utf8Lenient.decode(bytes);
|
|
125
|
+
}
|
|
126
|
+
/** Encodes a string as UTF-8. */ export function utf8Encode(text) {
|
|
127
|
+
return utf8Encoder.encode(text);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Decodes free text of unknown encoding — a JPEG COM segment, a GIF comment
|
|
131
|
+
* — as UTF-8 when it is valid UTF-8 and as Latin-1 otherwise. Neither format
|
|
132
|
+
* names an encoding; UTF-8 is what current tools write and Latin-1 is what
|
|
133
|
+
* older ones did, and a Latin-1 accent is almost never valid UTF-8.
|
|
134
|
+
*/ export function decodeFreeText(bytes) {
|
|
135
|
+
try {
|
|
136
|
+
return utf8Strict.decode(bytes);
|
|
137
|
+
} catch (unused) {
|
|
138
|
+
return latin1Decode(bytes);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** Decodes big-endian UTF-16 code units (ICC `mluc`/`desc` text). */ export function utf16beDecode(bytes) {
|
|
142
|
+
let out = '';
|
|
143
|
+
const units = [];
|
|
144
|
+
for(let i = 0; i + 1 < bytes.length; i += 2){
|
|
145
|
+
units.push(readU16BE(bytes, i));
|
|
146
|
+
if (units.length === 0x2000) {
|
|
147
|
+
out += String.fromCharCode(...units);
|
|
148
|
+
units.length = 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return out + String.fromCharCode(...units);
|
|
152
|
+
}
|
|
153
|
+
/** Removes trailing NUL characters, which several writers terminate with. */ export function trimNul(text) {
|
|
154
|
+
let end = text.length;
|
|
155
|
+
while(end > 0 && text.charCodeAt(end - 1) === 0)end -= 1;
|
|
156
|
+
return text.slice(0, end);
|
|
157
|
+
}
|
|
158
|
+
/** Concatenates byte arrays into one new array. */ export function concatBytes(parts) {
|
|
159
|
+
let length = 0;
|
|
160
|
+
for (const part of parts)length += part.length;
|
|
161
|
+
const out = new Uint8Array(length);
|
|
162
|
+
let offset = 0;
|
|
163
|
+
for (const part of parts){
|
|
164
|
+
out.set(part, offset);
|
|
165
|
+
offset += part.length;
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
let crcTable = null;
|
|
170
|
+
/**
|
|
171
|
+
* CRC-32 (ISO 3309 / ITU-T V.42, polynomial 0xEDB88320), the checksum every
|
|
172
|
+
* PNG chunk ends with (PNG 3rd edition, 5.5). Computed here rather than
|
|
173
|
+
* through `zlib.crc32`, which older Node releases do not have.
|
|
174
|
+
*/ export function crc32(...parts) {
|
|
175
|
+
if (!crcTable) {
|
|
176
|
+
crcTable = new Uint32Array(256);
|
|
177
|
+
for(let n = 0; n < 256; n += 1){
|
|
178
|
+
let c = n;
|
|
179
|
+
for(let k = 0; k < 8; k += 1){
|
|
180
|
+
c = c & 1 ? 0xedb88320 ^ c >>> 1 : c >>> 1;
|
|
181
|
+
}
|
|
182
|
+
crcTable[n] = c >>> 0;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
let crc = 0xffffffff;
|
|
186
|
+
for (const part of parts){
|
|
187
|
+
for(let i = 0; i < part.length; i += 1){
|
|
188
|
+
var _crcTable_, _part_i;
|
|
189
|
+
crc = ((_crcTable_ = crcTable[(crc ^ ((_part_i = part[i]) != null ? _part_i : 0)) & 0xff]) != null ? _crcTable_ : 0) ^ crc >>> 8;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* The sentence every writer throws when a block will not fit its container
|
|
196
|
+
* — a JPEG segment tops out at 64 KB.
|
|
197
|
+
*/ export const METADATA_TOO_LARGE = "This file's embedded metadata is too large to edit here.";
|
|
198
|
+
/** The sentence a writer throws when the file's own structure is broken. */ export const FILE_DAMAGED = "This file's structure is damaged, so its embedded metadata cannot be edited safely.";
|
|
199
|
+
|
|
200
|
+
//# sourceMappingURL=image-blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/aglyn/src/lib/app-utils/media-embedded-metadata/image-blocks.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The raw metadata BLOCKS of an image container (AGL-3331), and the byte\n * helpers the container modules share.\n *\n * Each image format hides the same few payloads in its own wrapper — EXIF is\n * a JPEG APP1 segment, a PNG `eXIf` chunk, a WebP `EXIF` chunk and a HEIF\n * item — and the container modules (`jpeg.ts`, `png.ts`, `webp.ts`, `gif.ts`,\n * `heif.ts`) do nothing but find those payloads and, for the writable\n * formats, put new ones back. They never interpret EXIF, IPTC or XMP; the\n * block readers do, over the {@link ImageBlocks} handed to them. Keeping the\n * split is what lets one EXIF parser serve four containers.\n */\n\n/** One PNG text chunk (PNG 3rd edition, 11.3.3). */\nexport interface PngTextChunk {\n /** 1 to 79 Latin-1 characters. */\n keyword: string\n text: string\n type: 'tEXt' | 'zTXt' | 'iTXt'\n /** `iTXt` only: the RFC 3066 language tag, when there is one. */\n language?: string\n /** `iTXt` only: the keyword translated into `language`. */\n translatedKeyword?: string\n}\n\n/**\n * The metadata payloads found in one image, unwrapped from their container.\n * A key is absent when the file does not carry that block.\n */\nexport interface ImageBlocks {\n /**\n * TIFF-structured EXIF, starting at the byte-order mark (`II*\\0` or\n * `MM\\0*`): the JPEG `Exif\\0\\0` prefix and HEIF's 4-byte header offset are\n * already stripped.\n */\n exif?: Uint8Array\n /** The standard (main) XMP packet, decoded as UTF-8. */\n xmp?: string\n /**\n * Photoshop Image Resource Blocks — the JPEG APP13 payload after\n * `Photoshop 3.0\\0`, with several consecutive APP13 segments concatenated\n * in file order the way Photoshop splits a large one.\n */\n irb?: Uint8Array\n /** JPEG COM segments and GIF comment extensions, in file order. */\n comments?: string[]\n /** Every PNG text chunk except the XMP one, in file order. */\n pngText?: PngTextChunk[]\n /**\n * The ICC profile: JPEG APP2 `ICC_PROFILE` chunks reassembled by sequence\n * number, a PNG `iCCP` inflated, a WebP `ICCP`, a GIF `ICCRGBG1`\n * application extension, or a HEIF `colr` box of type `prof`/`rICC`.\n */\n icc?: Uint8Array\n}\n\n/**\n * An edit to an image's blocks. For every key, `undefined` keeps the block\n * as it is and `null` removes it.\n *\n * A writer throws `EmbeddedWriteError` when asked to SET a block its\n * container has no place for (IRB in a PNG, a text chunk in a JPEG); asking\n * to remove one is a no-op, since the file already does not carry it.\n */\nexport interface ImageBlockUpdate {\n exif?: Uint8Array | null\n xmp?: string | null\n irb?: Uint8Array | null\n /** PNG only: set or remove a text chunk by keyword. */\n pngText?: Record<string, string | null>\n}\n\n// ---------------------------------------------------------------------------\n// Byte helpers shared by the container modules. Every read is bounds-safe: a\n// byte past the end reads as 0, so a caller that checked its range once can\n// read without a second check, and one that did not gets zeros, not a throw.\n// ---------------------------------------------------------------------------\n\n/** Reads an unsigned 16-bit big-endian integer. */\nexport function readU16BE(bytes: Uint8Array, offset: number): number {\n return ((bytes[offset] ?? 0) << 8) | (bytes[offset + 1] ?? 0)\n}\n\n/** Reads an unsigned 16-bit little-endian integer. */\nexport function readU16LE(bytes: Uint8Array, offset: number): number {\n return (bytes[offset] ?? 0) | ((bytes[offset + 1] ?? 0) << 8)\n}\n\n/** Reads an unsigned 24-bit little-endian integer. */\nexport function readU24LE(bytes: Uint8Array, offset: number): number {\n return (\n (bytes[offset] ?? 0) |\n ((bytes[offset + 1] ?? 0) << 8) |\n ((bytes[offset + 2] ?? 0) << 16)\n )\n}\n\n/** Reads an unsigned 32-bit big-endian integer. */\nexport function readU32BE(bytes: Uint8Array, offset: number): number {\n return (\n (bytes[offset] ?? 0) * 0x1000000 +\n (((bytes[offset + 1] ?? 0) << 16) |\n ((bytes[offset + 2] ?? 0) << 8) |\n (bytes[offset + 3] ?? 0))\n )\n}\n\n/** Reads an unsigned 32-bit little-endian integer. */\nexport function readU32LE(bytes: Uint8Array, offset: number): number {\n return (\n (bytes[offset + 3] ?? 0) * 0x1000000 +\n (((bytes[offset + 2] ?? 0) << 16) |\n ((bytes[offset + 1] ?? 0) << 8) |\n (bytes[offset] ?? 0))\n )\n}\n\n/** Writes an unsigned 16-bit big-endian integer. */\nexport function writeU16BE(bytes: Uint8Array, offset: number, value: number) {\n bytes[offset] = (value >>> 8) & 0xff\n bytes[offset + 1] = value & 0xff\n}\n\n/** Writes an unsigned 32-bit big-endian integer. */\nexport function writeU32BE(bytes: Uint8Array, offset: number, value: number) {\n bytes[offset] = (value >>> 24) & 0xff\n bytes[offset + 1] = (value >>> 16) & 0xff\n bytes[offset + 2] = (value >>> 8) & 0xff\n bytes[offset + 3] = value & 0xff\n}\n\n/** Writes an unsigned 32-bit little-endian integer. */\nexport function writeU32LE(bytes: Uint8Array, offset: number, value: number) {\n bytes[offset] = value & 0xff\n bytes[offset + 1] = (value >>> 8) & 0xff\n bytes[offset + 2] = (value >>> 16) & 0xff\n bytes[offset + 3] = (value >>> 24) & 0xff\n}\n\n/** Whether `bytes` holds exactly `magic` at `offset`. */\nexport function bytesAt(\n bytes: Uint8Array,\n offset: number,\n magic: Uint8Array,\n): boolean {\n if (offset < 0 || offset + magic.length > bytes.length) return false\n for (let i = 0; i < magic.length; i += 1) {\n if (bytes[offset + i] !== magic[i]) return false\n }\n return true\n}\n\n/** The first index of `needle` in `bytes` at or after `from`, or -1. */\nexport function indexOfBytes(\n bytes: Uint8Array,\n needle: Uint8Array,\n from = 0,\n to = bytes.length,\n): number {\n const first = needle[0]\n if (first === undefined) return -1\n const last = Math.min(to, bytes.length) - needle.length\n for (let i = Math.max(0, from); i <= last; i += 1) {\n if (bytes[i] === first && bytesAt(bytes, i, needle)) return i\n }\n return -1\n}\n\n/** The ASCII (Latin-1) bytes of a string of code points below 256. */\nexport function asciiBytes(text: string): Uint8Array {\n const out = new Uint8Array(text.length)\n for (let i = 0; i < text.length; i += 1) out[i] = text.charCodeAt(i) & 0xff\n return out\n}\n\n/** Reads `length` bytes at `offset` as a four-character code or tag. */\nexport function readAscii(\n bytes: Uint8Array,\n offset: number,\n length: number,\n): string {\n let out = ''\n const end = Math.min(bytes.length, offset + length)\n for (let i = Math.max(0, offset); i < end; i += 1) {\n out += String.fromCharCode(bytes[i] ?? 0)\n }\n return out\n}\n\n/** Decodes ISO 8859-1, where every byte is the code point of its value. */\nexport function latin1Decode(bytes: Uint8Array): string {\n let out = ''\n // Chunked so a long text chunk never builds a huge argument list.\n for (let i = 0; i < bytes.length; i += 0x2000) {\n out += String.fromCharCode(...bytes.subarray(i, i + 0x2000))\n }\n return out\n}\n\n/**\n * Encodes a string as ISO 8859-1, or `null` when any character is outside\n * it (the signal for PNG to use `iTXt` instead of `tEXt`).\n */\nexport function latin1Encode(text: string): Uint8Array | null {\n const out = new Uint8Array(text.length)\n for (let i = 0; i < text.length; i += 1) {\n const code = text.charCodeAt(i)\n if (code > 0xff) return null\n out[i] = code\n }\n return out\n}\n\nconst utf8Lenient = new TextDecoder('utf-8')\nconst utf8Strict = new TextDecoder('utf-8', { fatal: true })\nconst utf8Encoder = new TextEncoder()\n\n/** Decodes UTF-8, replacing malformed sequences rather than throwing. */\nexport function utf8Decode(bytes: Uint8Array): string {\n return utf8Lenient.decode(bytes)\n}\n\n/** Encodes a string as UTF-8. */\nexport function utf8Encode(text: string): Uint8Array {\n return utf8Encoder.encode(text)\n}\n\n/**\n * Decodes free text of unknown encoding — a JPEG COM segment, a GIF comment\n * — as UTF-8 when it is valid UTF-8 and as Latin-1 otherwise. Neither format\n * names an encoding; UTF-8 is what current tools write and Latin-1 is what\n * older ones did, and a Latin-1 accent is almost never valid UTF-8.\n */\nexport function decodeFreeText(bytes: Uint8Array): string {\n try {\n return utf8Strict.decode(bytes)\n } catch {\n return latin1Decode(bytes)\n }\n}\n\n/** Decodes big-endian UTF-16 code units (ICC `mluc`/`desc` text). */\nexport function utf16beDecode(bytes: Uint8Array): string {\n let out = ''\n const units: number[] = []\n for (let i = 0; i + 1 < bytes.length; i += 2) {\n units.push(readU16BE(bytes, i))\n if (units.length === 0x2000) {\n out += String.fromCharCode(...units)\n units.length = 0\n }\n }\n return out + String.fromCharCode(...units)\n}\n\n/** Removes trailing NUL characters, which several writers terminate with. */\nexport function trimNul(text: string): string {\n let end = text.length\n while (end > 0 && text.charCodeAt(end - 1) === 0) end -= 1\n return text.slice(0, end)\n}\n\n/** Concatenates byte arrays into one new array. */\nexport function concatBytes(parts: readonly Uint8Array[]): Uint8Array {\n let length = 0\n for (const part of parts) length += part.length\n const out = new Uint8Array(length)\n let offset = 0\n for (const part of parts) {\n out.set(part, offset)\n offset += part.length\n }\n return out\n}\n\nlet crcTable: Uint32Array | null = null\n\n/**\n * CRC-32 (ISO 3309 / ITU-T V.42, polynomial 0xEDB88320), the checksum every\n * PNG chunk ends with (PNG 3rd edition, 5.5). Computed here rather than\n * through `zlib.crc32`, which older Node releases do not have.\n */\nexport function crc32(...parts: Uint8Array[]): number {\n if (!crcTable) {\n crcTable = new Uint32Array(256)\n for (let n = 0; n < 256; n += 1) {\n let c = n\n for (let k = 0; k < 8; k += 1) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1\n }\n crcTable[n] = c >>> 0\n }\n }\n let crc = 0xffffffff\n for (const part of parts) {\n for (let i = 0; i < part.length; i += 1) {\n crc = (crcTable[(crc ^ (part[i] ?? 0)) & 0xff] ?? 0) ^ (crc >>> 8)\n }\n }\n return (crc ^ 0xffffffff) >>> 0\n}\n\n/**\n * The sentence every writer throws when a block will not fit its container\n * — a JPEG segment tops out at 64 KB.\n */\nexport const METADATA_TOO_LARGE =\n \"This file's embedded metadata is too large to edit here.\"\n\n/** The sentence a writer throws when the file's own structure is broken. */\nexport const FILE_DAMAGED =\n \"This file's structure is damaged, so its embedded metadata cannot be edited safely.\"\n"],"names":["readU16BE","bytes","offset","readU16LE","readU24LE","readU32BE","readU32LE","writeU16BE","value","writeU32BE","writeU32LE","bytesAt","magic","length","i","indexOfBytes","needle","from","to","first","undefined","last","Math","min","max","asciiBytes","text","out","Uint8Array","charCodeAt","readAscii","end","String","fromCharCode","latin1Decode","subarray","latin1Encode","code","utf8Lenient","TextDecoder","utf8Strict","fatal","utf8Encoder","TextEncoder","utf8Decode","decode","utf8Encode","encode","decodeFreeText","utf16beDecode","units","push","trimNul","slice","concatBytes","parts","part","set","crcTable","crc32","Uint32Array","n","c","k","crc","METADATA_TOO_LARGE","FILE_DAMAGED"],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
* Reads the metadata a media file carries inside its own bytes, and writes
|
|
19
|
+
* edits back into them without re-encoding anything (AGL-3331).
|
|
20
|
+
*
|
|
21
|
+
* This file is the dispatcher. It sniffs the container, hands the bytes to
|
|
22
|
+
* the format module, and folds what comes back — up to three copies of a
|
|
23
|
+
* photo's caption, from XMP, IPTC and EXIF — into the one list of fields a
|
|
24
|
+
* media document stores. Writing is the same trip in reverse: one edit fans
|
|
25
|
+
* out to every block that already holds that idea, so no stale copy is left
|
|
26
|
+
* for the next reader to prefer.
|
|
27
|
+
*
|
|
28
|
+
* Server-only: exposed through `@aglyn/aglyn/server` and never the client
|
|
29
|
+
* barrel. The client half — the catalog, the value formats, the edit rules —
|
|
30
|
+
* is `../media-embedded-fields`.
|
|
31
|
+
*/
|
|
32
|
+
import { type MediaEmbeddedField, type MediaEmbeddedFormat, type MediaEmbeddedMetadata, type MediaEmbeddedPatch } from '../media-embedded-fields';
|
|
33
|
+
import { bytesReader, EmbeddedWriteError, type EmbeddedByteReader, type EmbeddedCandidate } from './types';
|
|
34
|
+
export { bytesReader, EmbeddedWriteError };
|
|
35
|
+
export type { EmbeddedByteReader, EmbeddedCandidate };
|
|
36
|
+
/**
|
|
37
|
+
* The most of a file the reader will pull into memory, by format.
|
|
38
|
+
*
|
|
39
|
+
* Every one is the upload ceiling for the family, so an asset the DAM
|
|
40
|
+
* accepted is always readable; the numbers exist so a future raise of a
|
|
41
|
+
* ceiling does not silently turn this into a 500 MB download. Video is read
|
|
42
|
+
* by range — its metadata lives in one box, not across the file — and its
|
|
43
|
+
* cap is on that box (see `mp4.ts`).
|
|
44
|
+
*/
|
|
45
|
+
export declare const MEDIA_EMBEDDED_READ_MAX_BYTES: Record<Exclude<MediaEmbeddedFormat, 'mp4' | 'webm'>, number>;
|
|
46
|
+
/**
|
|
47
|
+
* Which reader a file gets, from its first bytes — the stored content type
|
|
48
|
+
* only breaks the ties the bytes cannot (an ISOBMFF `ftyp` is a HEIC photo
|
|
49
|
+
* or an MP4 film; a ZIP is a Word file or a ZIP). A type label is the
|
|
50
|
+
* uploader's claim and the signature is the file's, so the signature wins
|
|
51
|
+
* wherever it can speak.
|
|
52
|
+
*/
|
|
53
|
+
export declare function embeddedFormatFor(contentType: string, head: Uint8Array): MediaEmbeddedFormat | null;
|
|
54
|
+
/**
|
|
55
|
+
* Fold every block's candidates into the stored field list.
|
|
56
|
+
*
|
|
57
|
+
* One field per key, valued from the most-believed source that holds it and
|
|
58
|
+
* naming every source that does. A value clipped to the stored cap is shown
|
|
59
|
+
* and NOT offered for editing: saving it back would write the clipped text
|
|
60
|
+
* over the whole one, which is data loss the person never asked for.
|
|
61
|
+
*/
|
|
62
|
+
export declare function mergeEmbeddedCandidates(format: MediaEmbeddedFormat, candidates: EmbeddedCandidate[]): {
|
|
63
|
+
fields: MediaEmbeddedField[];
|
|
64
|
+
truncated: boolean;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Read a stored file's embedded metadata.
|
|
68
|
+
*
|
|
69
|
+
* Returns `null` when the format has no reader or the file is past the read
|
|
70
|
+
* cap — the drawer then simply has no "In the file" section, which is the
|
|
71
|
+
* honest thing to show about a CSV. Never throws on the bytes: every format
|
|
72
|
+
* module is written to return what it could read from a hostile file.
|
|
73
|
+
*/
|
|
74
|
+
export declare function readMediaEmbeddedMetadata(options: {
|
|
75
|
+
contentType: string;
|
|
76
|
+
reader: EmbeddedByteReader;
|
|
77
|
+
contentSha256?: string;
|
|
78
|
+
}): Promise<MediaEmbeddedMetadata | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Write an edit into a file's bytes and return the new bytes.
|
|
81
|
+
*
|
|
82
|
+
* The patch is validated against the catalog first (the route has already
|
|
83
|
+
* done so for the person's benefit; this is for every other caller), then
|
|
84
|
+
* written by the format module. Throws `EmbeddedWriteError` — a sentence for
|
|
85
|
+
* the person who asked — when the file cannot take it safely; anything else
|
|
86
|
+
* thrown is a fault.
|
|
87
|
+
*/
|
|
88
|
+
export declare function writeMediaEmbeddedMetadata(options: {
|
|
89
|
+
contentType: string;
|
|
90
|
+
bytes: Uint8Array;
|
|
91
|
+
patch: MediaEmbeddedPatch;
|
|
92
|
+
now?: Date;
|
|
93
|
+
}): Uint8Array;
|