@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 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/aglyn/src/lib/app-utils/media-embedded-metadata/exif.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 * EXIF, and the TIFF structure that carries it (AGL-3331).\n *\n * A JPEG's APP1 `Exif\\0\\0` segment, a WebP `EXIF` chunk, a PNG `eXIf` chunk\n * and a TIFF file all hold the same thing: a TIFF header followed by image\n * file directories (IFDs), TIFF 6.0 §2, which EXIF 2.32 §4.5 adopts as is.\n * Every function here takes the bytes from the byte-order mark (`II*\\0` or\n * `MM\\0*`) on; containers strip their own framing first.\n *\n * ## Reading\n *\n * {@link readExif} maps IFD0, the Exif IFD (pointer 0x8769) and the GPS IFD\n * (pointer 0x8825) onto the canonical keys of `media-embedded-fields.ts`.\n * Strings are ASCII by the spec and UTF-8 in real files, so they decode as\n * UTF-8 and fall back to Latin-1. Every offset and count is checked against\n * the block, the walk refuses cycles, and a damaged block yields whatever it\n * could read rather than an exception. BigTIFF (version 43) reads too.\n *\n * ## Writing without moving anything\n *\n * A TIFF block is full of absolute offsets this module cannot see: a\n * MakerNote's private IFD points into itself by offset from the TIFF header,\n * a thumbnail is found through IFD1, a TIFF file's pixels through\n * StripOffsets. So the writer NEVER MOVES A BYTE IT DID NOT CREATE:\n *\n * - A value that fits its old slot (four bytes inside the entry, or the old\n * out-of-line length) is overwritten in place and NUL-filled.\n * - A larger value is appended at the end of the block and its entry\n * repointed. An entry is a fixed 12 bytes, so nothing else shifts.\n * - Adding or removing an entry relocates THAT IFD: a fresh copy, entries\n * sorted by tag (TIFF 6.0 §2 \"the entries must be sorted in ascending\n * order by the Tag\"), next-IFD pointer preserved, goes at the end, and\n * whatever pointed at the old one (the header for IFD0, 0x8769, 0x8825)\n * is repointed.\n * - Bytes nothing references any more (a replaced value's old slot, a\n * relocated IFD's old table, a scrubbed GPS IFD) are zeroed, so a removed\n * value is gone from the file rather than merely unreferenced.\n *\n * Before overwriting or zeroing an old slot the writer checks that no other\n * structure it knows of (another entry's value, an IFD table, strips, tiles,\n * the thumbnail) claims any of those bytes; a shared slot is left alone and\n * the new value appended instead.\n */\n\nimport {\n EmbeddedWriteError,\n type EmbeddedCandidate,\n type EmbeddedPatch,\n} from './types'\n\n/**\n * Field types: TIFF 6.0 §2 \"Types\", TIFF Technical Note 1 (IFD) and the\n * BigTIFF extension (LONG8, SLONG8, IFD8).\n */\nexport const TIFF_TYPE = {\n BYTE: 1,\n ASCII: 2,\n SHORT: 3,\n LONG: 4,\n RATIONAL: 5,\n SBYTE: 6,\n UNDEFINED: 7,\n SSHORT: 8,\n SLONG: 9,\n SRATIONAL: 10,\n FLOAT: 11,\n DOUBLE: 12,\n IFD: 13,\n LONG8: 16,\n SLONG8: 17,\n IFD8: 18,\n} as const\n\nconst T = TIFF_TYPE\n\n/** Bytes per value, by field type. An unknown type has no known extent. */\nconst TYPE_SIZE: Readonly<Record<number, number>> = {\n [T.BYTE]: 1,\n [T.ASCII]: 1,\n [T.SHORT]: 2,\n [T.LONG]: 4,\n [T.RATIONAL]: 8,\n [T.SBYTE]: 1,\n [T.UNDEFINED]: 1,\n [T.SSHORT]: 2,\n [T.SLONG]: 4,\n [T.SRATIONAL]: 8,\n [T.FLOAT]: 4,\n [T.DOUBLE]: 8,\n [T.IFD]: 4,\n [T.LONG8]: 8,\n [T.SLONG8]: 8,\n [T.IFD8]: 8,\n}\n\n/** Tag numbers: TIFF 6.0 Appendix A and EXIF 2.32 §4.6. */\nconst TAG = {\n imageDescription: 0x010e,\n make: 0x010f,\n model: 0x0110,\n stripOffsets: 0x0111,\n orientation: 0x0112,\n stripByteCounts: 0x0117,\n software: 0x0131,\n dateTime: 0x0132,\n artist: 0x013b,\n tileOffsets: 0x0144,\n tileByteCounts: 0x0145,\n subIfds: 0x014a,\n jpegInterchangeFormat: 0x0201,\n jpegInterchangeFormatLength: 0x0202,\n copyright: 0x8298,\n exposureTime: 0x829a,\n fNumber: 0x829d,\n exifIfd: 0x8769,\n gpsIfd: 0x8825,\n iso: 0x8827,\n dateTimeOriginal: 0x9003,\n offsetTime: 0x9010,\n offsetTimeOriginal: 0x9011,\n flash: 0x9209,\n focalLength: 0x920a,\n makerNote: 0x927c,\n userComment: 0x9286,\n xpTitle: 0x9c9b,\n xpComment: 0x9c9c,\n xpAuthor: 0x9c9d,\n xpKeywords: 0x9c9e,\n interopIfd: 0xa005,\n lensModel: 0xa434,\n} as const\n\n/** GPS IFD tags, EXIF 2.32 §4.6.6. */\nconst GPS = {\n latitudeRef: 0x0001,\n latitude: 0x0002,\n longitudeRef: 0x0003,\n longitude: 0x0004,\n altitudeRef: 0x0005,\n altitude: 0x0006,\n} as const\n\n/**\n * Tags that locate other structures by offset. Rewriting one would orphan\n * or corrupt what it points at, so {@link writeTiffTags} refuses them.\n */\nconst STRUCTURAL_TAGS: ReadonlySet<number> = new Set([\n TAG.stripOffsets,\n TAG.stripByteCounts,\n TAG.tileOffsets,\n TAG.tileByteCounts,\n TAG.subIfds,\n TAG.jpegInterchangeFormat,\n TAG.jpegInterchangeFormatLength,\n TAG.exifIfd,\n TAG.gpsIfd,\n TAG.interopIfd,\n TAG.makerNote,\n])\n\n/** Offset/length tag pairs whose data the writer must never touch. */\nconst DATA_PAIRS: ReadonlyArray<readonly [number, number]> = [\n [TAG.stripOffsets, TAG.stripByteCounts],\n [TAG.tileOffsets, TAG.tileByteCounts],\n [TAG.jpegInterchangeFormat, TAG.jpegInterchangeFormatLength],\n]\n\n/** Bounds on the walk, far above anything a camera or editor writes. */\nconst MAX_IFDS = 64\nconst MAX_DATA_RANGES = 65536\n\n/** EXIF 2.32 §4.6.5 Orientation, worded as ExifTool prints it. */\nconst ORIENTATION: Readonly<Record<number, string>> = {\n 1: 'Horizontal (normal)',\n 2: 'Mirror horizontal',\n 3: 'Rotate 180',\n 4: 'Mirror vertical',\n 5: 'Mirror horizontal and rotate 270 CW',\n 6: 'Rotate 90 CW',\n 7: 'Mirror horizontal and rotate 90 CW',\n 8: 'Rotate 270 CW',\n}\n\n/** The IFDs a caller can address. */\nexport type TiffDirectory = 'ifd0' | 'exif' | 'gps'\n\n/**\n * One tag to set or remove. `value` is the raw value bytes IN THE BLOCK'S\n * BYTE ORDER (the same bytes {@link readTiffTagBytes} returns), and `count`\n * defaults to `value.length` divided by the type's size. `null` removes the\n * entry.\n */\nexport interface TiffTagWrite {\n ifd: TiffDirectory\n tag: number\n type: number\n count?: number\n value: Uint8Array | null\n}\n\n/** Everything one pass of {@link editTiff} can do. */\nexport interface TiffEdit {\n /** Canonical-key edits, applied to tags that already exist. */\n patch?: EmbeddedPatch\n /** Raw tag writes, applied after the patch (a later write wins). */\n writes?: readonly TiffTagWrite[]\n /** Whether `writes` may add tags that are not there yet. */\n allowAdd?: boolean\n /** The largest block the container can hold. */\n maxLength?: number\n}\n\n// ---------------------------------------------------------------------------\n// Bytes\n// ---------------------------------------------------------------------------\n\nfunction get16(b: Uint8Array, at: number, little: boolean): number {\n const x = b[at] ?? 0\n const y = b[at + 1] ?? 0\n return little ? x | (y << 8) : (x << 8) | y\n}\n\nfunction get32(b: Uint8Array, at: number, little: boolean): number {\n const lo = get16(b, little ? at : at + 2, little)\n const hi = get16(b, little ? at + 2 : at, little)\n return hi * 0x10000 + lo\n}\n\n/**\n * A 64-bit value as a double. Past 2^53 it loses precision, which never\n * matters: anything that large fails every bounds check anyway.\n */\nfunction get64(b: Uint8Array, at: number, little: boolean): number {\n const lo = get32(b, little ? at : at + 4, little)\n const hi = get32(b, little ? at + 4 : at, little)\n return hi * 0x100000000 + lo\n}\n\nfunction put16(b: Uint8Array, at: number, value: number, little: boolean) {\n b[little ? at : at + 1] = value & 0xff\n b[little ? at + 1 : at] = (value >>> 8) & 0xff\n}\n\nfunction put32(b: Uint8Array, at: number, value: number, little: boolean) {\n put16(b, little ? at : at + 2, value & 0xffff, little)\n put16(b, little ? at + 2 : at, Math.floor(value / 0x10000) & 0xffff, little)\n}\n\nfunction encode32(value: number, little: boolean): Uint8Array {\n const out = new Uint8Array(4)\n put32(out, 0, value, little)\n return out\n}\n\nfunction concat(...parts: ArrayLike<number>[]): Uint8Array {\n const out = new Uint8Array(parts.reduce((n, part) => n + part.length, 0))\n let at = 0\n for (const part of parts) {\n out.set(part, at)\n at += part.length\n }\n return out\n}\n\nfunction sameBytes(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false\n return true\n}\n\n// ---------------------------------------------------------------------------\n// Text\n// ---------------------------------------------------------------------------\n\nconst utf8Strict = new TextDecoder('utf-8', { fatal: true })\nconst utf16le = new TextDecoder('utf-16le')\nconst encoder = new TextEncoder()\n\n/**\n * Windows-1252's 0x80–0x9F, the only range where it differs from ISO\n * 8859-1. \"Latin-1\" text in the wild is Windows-1252, and the WHATWG\n * Encoding standard decodes the `latin1` label the same way.\n */\nconst CP1252_HIGH = [\n 0x20ac, 0x81, 0x201a, 0x192, 0x201e, 0x2026, 0x2020, 0x2021, 0x2c6, 0x2030,\n 0x160, 0x2039, 0x152, 0x8d, 0x17d, 0x8f, 0x90, 0x2018, 0x2019, 0x201c, 0x201d,\n 0x2022, 0x2013, 0x2014, 0x2dc, 0x2122, 0x161, 0x203a, 0x153, 0x9d, 0x17e,\n 0x178,\n]\n\nfunction decodeLatin1(bytes: Uint8Array): string {\n let out = ''\n for (const byte of bytes) {\n out += String.fromCharCode(\n byte >= 0x80 && byte < 0xa0 ? (CP1252_HIGH[byte - 0x80] ?? byte) : byte,\n )\n }\n return out\n}\n\n/** Whether the bytes are well-formed UTF-8. */\nexport function isUtf8(bytes: Uint8Array): boolean {\n try {\n utf8Strict.decode(bytes)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Text in a field whose declared charset nobody honors: UTF-8 when the\n * bytes are valid UTF-8 (pure ASCII is), Latin-1 otherwise. Shared with the\n * IPTC reader, which has the same problem.\n */\nexport function decodeLegacyText(bytes: Uint8Array): string {\n try {\n return utf8Strict.decode(bytes)\n } catch {\n return decodeLatin1(bytes)\n }\n}\n\n/** Text up to the first NUL, decoded, with surrounding whitespace removed. */\nfunction cleanText(bytes: Uint8Array): string {\n const nul = bytes.indexOf(0)\n return decodeLegacyText(nul >= 0 ? bytes.subarray(0, nul) : bytes).trim()\n}\n\nfunction decodeUcs2(bytes: Uint8Array, little: boolean): string {\n const even = bytes.subarray(0, bytes.length - (bytes.length % 2))\n if (little) return utf16le.decode(even)\n const swapped = new Uint8Array(even.length)\n for (let i = 0; i + 1 < even.length; i += 2) {\n swapped[i] = even[i + 1] ?? 0\n swapped[i + 1] = even[i] ?? 0\n }\n return utf16le.decode(swapped)\n}\n\nfunction cleanUcs2(bytes: Uint8Array, little: boolean): string {\n const text = decodeUcs2(bytes, little)\n const nul = text.indexOf('\\0')\n return (nul >= 0 ? text.slice(0, nul) : text).trim()\n}\n\nfunction encodeUcs2(text: string, little: boolean): Uint8Array {\n const out = new Uint8Array(text.length * 2)\n for (let i = 0; i < text.length; i++)\n put16(out, i * 2, text.charCodeAt(i), little)\n return out\n}\n\nfunction isAscii(text: string): boolean {\n for (let i = 0; i < text.length; i++)\n if (text.charCodeAt(i) > 0x7f) return false\n return true\n}\n\n/** An ASCII-typed value: UTF-8, as real files hold it, NUL-terminated. */\nfunction asciiValue(text: string): Uint8Array {\n return concat(encoder.encode(text), [0])\n}\n\n/** A Windows XP tag: UCS-2 little-endian whatever the block's order. */\nfunction xpValue(text: string): Uint8Array {\n return concat(encodeUcs2(text, true), [0, 0])\n}\n\nfunction splitList(text: string | null): string[] | null {\n if (!text) return null\n const items = [...new Set(text.split(';').map((item) => item.trim()))]\n const kept = items.filter(Boolean)\n return kept.length ? kept : null\n}\n\n/** A number with at most `places` decimals and no trailing zeros. */\nfunction trimNumber(value: number, places: number): string {\n const fixed = value.toFixed(places)\n return fixed.includes('.') ? fixed.replace(/\\.?0+$/, '') : fixed\n}\n\n// ---------------------------------------------------------------------------\n// Structure\n// ---------------------------------------------------------------------------\n\ninterface TiffHeader {\n little: boolean\n /** BigTIFF: 8-byte offsets and counts, 20-byte entries. Read-only. */\n big: boolean\n ifd0: number\n}\n\ninterface TiffEntry {\n tag: number\n type: number\n count: number\n /** Absolute offset of the entry itself. */\n at: number\n /** Absolute offset of the value; inside the entry when `inline`. */\n valueAt: number\n /** `count` times the type's size, or -1 for a type with no known size. */\n size: number\n inline: boolean\n /** Whether the whole value lies inside the block. */\n ok: boolean\n}\n\ninterface TiffIfd {\n at: number\n entries: TiffEntry[]\n /** The raw next-IFD offset; 0 when there is none. */\n next: number\n /** Bytes of the count, entries and next pointer that lie in the block. */\n length: number\n}\n\ninterface TiffTree {\n header: TiffHeader\n ifd0: TiffIfd | null\n exif: TiffIfd | null\n gps: TiffIfd | null\n /** Every IFD reached, for the writer's map of who owns which bytes. */\n all: TiffIfd[]\n}\n\nfunction readHeader(b: Uint8Array): TiffHeader | null {\n if (b.length < 8) return null\n const little = b[0] === 0x49 && b[1] === 0x49\n if (!little && !(b[0] === 0x4d && b[1] === 0x4d)) return null\n const version = get16(b, 2, little)\n if (version === 42) return { little, big: false, ifd0: get32(b, 4, little) }\n // BigTIFF: the offset size (always 8) and a reserved zero follow.\n if (version !== 43 || b.length < 16) return null\n if (get16(b, 4, little) !== 8 || get16(b, 6, little) !== 0) return null\n return { little, big: true, ifd0: get64(b, 8, little) }\n}\n\n/** Whether the bytes start with a TIFF header this module can read. */\nexport function isTiff(bytes: Uint8Array): boolean {\n return readHeader(bytes) !== null\n}\n\nfunction parseIfd(b: Uint8Array, h: TiffHeader, at: number): TiffIfd | null {\n const countSize = h.big ? 8 : 2\n const entrySize = h.big ? 20 : 12\n const pointerSize = h.big ? 8 : 4\n const headerSize = h.big ? 16 : 8\n if (!Number.isSafeInteger(at) || at < headerSize) return null\n if (at + countSize > b.length) return null\n const n = h.big ? get64(b, at, h.little) : get16(b, at, h.little)\n const entriesEnd = at + countSize + n * entrySize\n if (n > 0xffff || entriesEnd > b.length) return null\n const next =\n entriesEnd + pointerSize <= b.length\n ? h.big\n ? get64(b, entriesEnd, h.little)\n : get32(b, entriesEnd, h.little)\n : 0\n const entries: TiffEntry[] = []\n for (let i = 0; i < n; i++) {\n const e = at + countSize + i * entrySize\n const type = get16(b, e + 2, h.little)\n const count = h.big ? get64(b, e + 4, h.little) : get32(b, e + 4, h.little)\n const field = e + (h.big ? 12 : 8)\n const unit = TYPE_SIZE[type]\n const size = unit === undefined ? -1 : count * unit\n const inline = size >= 0 && size <= pointerSize\n const valueAt = inline\n ? field\n : h.big\n ? get64(b, field, h.little)\n : get32(b, field, h.little)\n entries.push({\n tag: get16(b, e, h.little),\n type,\n count,\n at: e,\n valueAt,\n size,\n inline,\n ok: size >= 0 && valueAt + size <= b.length,\n })\n }\n return {\n at,\n entries,\n next,\n length: Math.min(entriesEnd + pointerSize, b.length) - at,\n }\n}\n\n/** The index-th value of an integer-typed entry, or null. */\nfunction uintAt(\n b: Uint8Array,\n h: TiffHeader,\n e: TiffEntry | undefined,\n index: number,\n): number | null {\n if (!e?.ok || index < 0 || index >= e.count) return null\n const at = e.valueAt + index * (TYPE_SIZE[e.type] ?? 0)\n switch (e.type) {\n case T.BYTE:\n case T.UNDEFINED:\n return b[at] ?? null\n case T.SBYTE:\n return ((b[at] ?? 0) << 24) >> 24\n case T.SHORT:\n return get16(b, at, h.little)\n case T.SSHORT:\n return (get16(b, at, h.little) << 16) >> 16\n case T.LONG:\n case T.IFD:\n return get32(b, at, h.little)\n case T.SLONG:\n return get32(b, at, h.little) | 0\n case T.LONG8:\n case T.IFD8:\n return get64(b, at, h.little)\n default:\n return null\n }\n}\n\n/** The index-th value of a rational (or integer) entry, or null. */\nfunction rationalAt(\n b: Uint8Array,\n h: TiffHeader,\n e: TiffEntry | undefined,\n index: number,\n): number | null {\n if (!e?.ok || index < 0 || index >= e.count) return null\n if (e.type !== T.RATIONAL && e.type !== T.SRATIONAL) {\n return uintAt(b, h, e, index)\n }\n const at = e.valueAt + index * 8\n let num = get32(b, at, h.little)\n let den = get32(b, at + 4, h.little)\n if (e.type === T.SRATIONAL) {\n num |= 0\n den |= 0\n }\n return den === 0 ? null : num / den\n}\n\n/**\n * Walk IFD0, the Exif and GPS IFDs, and, only so the writer knows which\n * bytes they own, the Interop IFD, IFD0's chain (IFD1 holds the thumbnail)\n * and any SubIFDs. Each IFD is visited once, so a cycle ends the walk.\n */\nfunction walk(b: Uint8Array): TiffTree | null {\n const header = readHeader(b)\n if (!header) return null\n const seen = new Set<number>()\n const all: TiffIfd[] = []\n const visit = (at: number | null): TiffIfd | null => {\n if (!at || seen.has(at) || seen.size >= MAX_IFDS) return null\n seen.add(at)\n const ifd = parseIfd(b, header, at)\n if (ifd) all.push(ifd)\n return ifd\n }\n const pointer = (ifd: TiffIfd | null, tag: number, index = 0) =>\n uintAt(\n b,\n header,\n ifd?.entries.find((e) => e.tag === tag),\n index,\n )\n\n const ifd0 = visit(header.ifd0)\n const exif = visit(pointer(ifd0, TAG.exifIfd))\n const gps = visit(pointer(ifd0, TAG.gpsIfd))\n visit(pointer(exif, TAG.interopIfd))\n const chain: TiffIfd[] = []\n for (let ifd = ifd0; ifd && chain.length < MAX_IFDS; ifd = visit(ifd.next)) {\n chain.push(ifd)\n }\n for (const ifd of chain) {\n const subs = ifd.entries.find((e) => e.tag === TAG.subIfds)\n for (let i = 0; subs && i < Math.min(subs.count, MAX_IFDS); i++) {\n visit(pointer(ifd, TAG.subIfds, i))\n }\n }\n return { header, ifd0, exif, gps, all }\n}\n\nfunction entryOf(ifd: TiffIfd | null, tag: number): TiffEntry | undefined {\n return ifd?.entries.find((e) => e.tag === tag)\n}\n\nfunction valueBytes(\n b: Uint8Array,\n e: TiffEntry | undefined,\n): Uint8Array | null {\n return e?.ok ? b.subarray(e.valueAt, e.valueAt + e.size) : null\n}\n\n// ---------------------------------------------------------------------------\n// Reading\n// ---------------------------------------------------------------------------\n\n/**\n * EXIF 2.32 §4.6.5: \"YYYY:MM:DD HH:MM:SS\", blank-filled when unknown. A\n * date whose time is blank reads as a date alone, which is what the writer\n * produces for a date-only edit.\n */\nfunction exifDateToIso(raw: string, offset: string | null): string | null {\n const m =\n /^(\\d{4})[:-](\\d{2})[:-](\\d{2})(?:[ T](\\d{2}):(\\d{2})(?::(\\d{2}))?)?/.exec(\n raw.trim(),\n )\n if (!m) return null\n const [, year, month, day, hour, minute, second] = m\n if (!year || !month || !day || year === '0000') return null\n if (+month < 1 || +month > 12 || +day < 1 || +day > 31) return null\n let iso = `${year}-${month}-${day}`\n if (hour === undefined || minute === undefined) return iso\n if (+hour > 23 || +minute > 59 || +(second ?? 0) > 60) return iso\n iso += `T${hour}:${minute}:${second ?? '00'}`\n const zone = offset?.trim()\n const z = zone ? /^([+-])(\\d{2}):?(\\d{2})$/.exec(zone) : null\n if (zone === 'Z') iso += 'Z'\n else if (z) iso += `${z[1]}${z[2]}:${z[3]}`\n return iso\n}\n\n/** ExifTool's rule: a quarter second and shorter reads as a fraction. */\nfunction formatExposure(seconds: number | null): string | null {\n if (seconds === null || !Number.isFinite(seconds) || seconds <= 0) return null\n if (seconds < 0.25001) return `1/${Math.round(1 / seconds)} s`\n return `${trimNumber(seconds, 1)} s`\n}\n\n/** EXIF 2.32 §4.6.5 Flash: bit 0 fired, 1–2 return, 3–4 mode, 5, 6. */\nfunction describeFlash(value: number | null): string | null {\n if (value === null) return null\n const fired = (value & 1) === 1\n if (!fired && value & 0x20) return 'No flash function'\n const parts = [fired ? 'Fired' : 'Did not fire']\n const mode = (value >> 3) & 3\n if (mode === 1) parts.push('compulsory flash mode')\n else if (mode === 2) parts.push('flash suppressed')\n else if (mode === 3) parts.push('auto mode')\n const strobe = (value >> 1) & 3\n if (strobe === 2) parts.push('return not detected')\n else if (strobe === 3) parts.push('return detected')\n if (value & 0x40) parts.push('red-eye reduction')\n return parts.join(', ')\n}\n\n/**\n * UserComment's 8-byte character code, EXIF 2.32 §4.6.5 Table 9. JIS and\n * the undefined code are not decoded, and so are not written either.\n */\nfunction userCommentCode(bytes: Uint8Array): 'ASCII' | 'UNICODE' | null {\n const code = decodeLatin1(bytes.subarray(0, 8)).replace(/\\0+$/, '')\n return bytes.length >= 8 && (code === 'ASCII' || code === 'UNICODE')\n ? code\n : null\n}\n\n/**\n * The byte order of a UNICODE UserComment. The spec does not say; most\n * writers use the block's own order, Microsoft's use little-endian whatever\n * the block says, and a few add a BOM. Mostly-Latin text settles it: the\n * zero bytes of the high halves all sit on one side.\n */\nfunction unicodeOrder(\n body: Uint8Array,\n blockLittle: boolean,\n): { little: boolean; bom: boolean } {\n if (body[0] === 0xff && body[1] === 0xfe) return { little: true, bom: true }\n if (body[0] === 0xfe && body[1] === 0xff) return { little: false, bom: true }\n let highFirst = 0\n let highSecond = 0\n for (let i = 0; i + 1 < body.length && i < 4096; i += 2) {\n if (body[i] === 0 && body[i + 1] !== 0) highFirst++\n if (body[i + 1] === 0 && body[i] !== 0) highSecond++\n }\n if (highSecond > highFirst) return { little: true, bom: false }\n if (highFirst > highSecond) return { little: false, bom: false }\n return { little: blockLittle, bom: false }\n}\n\nfunction decodeUserComment(bytes: Uint8Array | null, little: boolean) {\n if (!bytes) return null\n const code = userCommentCode(bytes)\n const body = bytes.subarray(8)\n if (code === 'ASCII') return cleanText(body)\n if (code !== 'UNICODE') return null\n const order = unicodeOrder(body, little)\n return cleanUcs2(order.bom ? body.subarray(2) : body, order.little)\n}\n\nfunction gpsCoordinate(\n b: Uint8Array,\n h: TiffHeader,\n value: TiffEntry | undefined,\n ref: string | null,\n): number | null {\n const degrees = rationalAt(b, h, value, 0)\n if (degrees === null || !value) return null\n const minutes = value.count > 1 ? (rationalAt(b, h, value, 1) ?? 0) : 0\n const seconds = value.count > 2 ? (rationalAt(b, h, value, 2) ?? 0) : 0\n const decimal =\n Math.abs(degrees) + Math.abs(minutes) / 60 + Math.abs(seconds) / 3600\n if (!Number.isFinite(decimal)) return null\n const hemisphere = ref?.trim().charAt(0).toUpperCase()\n return hemisphere === 'S' || hemisphere === 'W' ? -decimal : decimal\n}\n\nfunction readInto(\n b: Uint8Array,\n tree: TiffTree,\n out: Map<string, string | string[]>,\n) {\n const { header: h, ifd0, exif, gps } = tree\n /** The first spelling found wins: standard tags are read before XP tags. */\n const set = (key: string, value: string | string[] | null) => {\n if (value === null || out.has(key)) return\n if (Array.isArray(value) ? value.length : value) out.set(key, value)\n }\n const text = (ifd: TiffIfd | null, tag: number) => {\n const bytes = valueBytes(b, entryOf(ifd, tag))\n return bytes ? cleanText(bytes) : null\n }\n const xp = (tag: number) => {\n const bytes = valueBytes(b, entryOf(ifd0, tag))\n return bytes ? cleanUcs2(bytes, true) : null\n }\n const numeric = (ifd: TiffIfd | null, tag: number) =>\n rationalAt(b, h, entryOf(ifd, tag), 0)\n\n set('title', xp(TAG.xpTitle))\n set('description', text(ifd0, TAG.imageDescription))\n set('keywords', splitList(xp(TAG.xpKeywords)))\n set(\n 'comment',\n decodeUserComment(valueBytes(b, entryOf(exif, TAG.userComment)), h.little),\n )\n set('comment', xp(TAG.xpComment))\n set('creator', splitList(text(ifd0, TAG.artist)))\n set('creator', splitList(xp(TAG.xpAuthor)))\n // EXIF 2.32 §4.6.5 Copyright: \"photographer\\0editor\\0\"; the first part.\n set('copyright', text(ifd0, TAG.copyright))\n\n if (gps) {\n const lat = gpsCoordinate(\n b,\n h,\n entryOf(gps, GPS.latitude),\n text(gps, GPS.latitudeRef),\n )\n const lon = gpsCoordinate(\n b,\n h,\n entryOf(gps, GPS.longitude),\n text(gps, GPS.longitudeRef),\n )\n if (lat !== null && lon !== null && lat <= 90 && lat >= -90) {\n if (lon <= 180 && lon >= -180) {\n set('gps', `${lat.toFixed(6)},${lon.toFixed(6)}`)\n }\n }\n const altitude = numeric(gps, GPS.altitude)\n if (altitude !== null && Number.isFinite(altitude)) {\n const below = uintAt(b, h, entryOf(gps, GPS.altitudeRef), 0) === 1\n const metres = below ? -Math.abs(altitude) : altitude\n set('gpsAltitude', `${trimNumber(metres, 1)} m`)\n }\n }\n\n const original = text(exif, TAG.dateTimeOriginal)\n if (original) {\n set(\n 'createdAt',\n exifDateToIso(original, text(exif, TAG.offsetTimeOriginal)),\n )\n }\n set('make', text(ifd0, TAG.make))\n set('model', text(ifd0, TAG.model))\n set('lens', text(exif, TAG.lensModel))\n set('exposure', formatExposure(numeric(exif, TAG.exposureTime)))\n const aperture = numeric(exif, TAG.fNumber)\n if (aperture !== null && Number.isFinite(aperture) && aperture > 0) {\n set('aperture', `f/${trimNumber(aperture, 1)}`)\n }\n const iso = uintAt(b, h, entryOf(exif, TAG.iso), 0)\n if (iso) set('iso', String(iso))\n const focal = numeric(exif, TAG.focalLength)\n if (focal !== null && Number.isFinite(focal) && focal > 0) {\n set('focalLength', `${trimNumber(focal, 1)} mm`)\n }\n set('flash', describeFlash(uintAt(b, h, entryOf(exif, TAG.flash), 0)))\n\n const modified = text(ifd0, TAG.dateTime)\n if (modified) {\n set('modifiedAt', exifDateToIso(modified, text(exif, TAG.offsetTime)))\n }\n set('software', text(ifd0, TAG.software))\n const orientation = uintAt(b, h, entryOf(ifd0, TAG.orientation), 0)\n set(\n 'orientation',\n orientation === null ? null : (ORIENTATION[orientation] ?? null),\n )\n}\n\n/**\n * Read the EXIF of a TIFF-structured block. Never throws: a damaged block\n * yields what could be read, a block that is not TIFF yields nothing.\n */\nexport function readExif(tiff: Uint8Array): EmbeddedCandidate[] {\n const values = new Map<string, string | string[]>()\n let big = false\n try {\n const tree = walk(tiff)\n if (tree) {\n big = tree.header.big\n readInto(tiff, tree, values)\n }\n } catch {\n // Every read is bounded; this only keeps a bug from failing an upload.\n }\n return [...values].map(([key, value]) => ({\n key,\n value,\n source: 'exif' as const,\n // A BigTIFF is read-only here, so none of its values can be written.\n ...(big ? { editable: false } : {}),\n }))\n}\n\n/**\n * The raw value of one tag, as stored: `bytes` is a view into `tiff`, in\n * the block's byte order. Null when the block, the IFD or the tag is\n * missing, or when the value runs past the end of the block.\n */\nexport function readTiffTagBytes(\n tiff: Uint8Array,\n ifd: TiffDirectory,\n tag: number,\n): { type: number; count: number; bytes: Uint8Array } | null {\n try {\n const tree = walk(tiff)\n const entry = entryOf(tree?.[ifd] ?? null, tag)\n const bytes = valueBytes(tiff, entry)\n return entry && bytes\n ? { type: entry.type, count: entry.count, bytes }\n : null\n } catch {\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// Writing\n// ---------------------------------------------------------------------------\n\n/** A strict ISO 8601 date, as `sanitizeEmbeddedPatch` admits it. */\nconst ISO_DATE =\n /^(\\d{4})-(\\d{2})-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})?)?$/\n\nconst IFD0_TEXT: ReadonlyArray<readonly [string, number]> = [\n ['description', TAG.imageDescription],\n ['make', TAG.make],\n ['model', TAG.model],\n ['software', TAG.software],\n]\n\n/** A patch value as one line; `undefined` when the key is not patched. */\nfunction patchText(\n value: string | string[] | null | undefined,\n separator: string,\n): string | null | undefined {\n if (value === undefined) return undefined\n if (value === null) return null\n const text = Array.isArray(value)\n ? value\n .map((item) => item.trim())\n .filter(Boolean)\n .join(separator)\n : value.trim()\n return text || null\n}\n\nfunction userCommentValue(\n current: Uint8Array | null,\n text: string | null,\n blockLittle: boolean,\n): Uint8Array | null | undefined {\n const code = current ? userCommentCode(current) : null\n if (!current || !code) return undefined\n if (text === null) return null\n if (code === 'ASCII' && isAscii(text)) {\n return concat(encoder.encode('ASCII\\0\\0\\0'), encoder.encode(text))\n }\n // Non-ASCII text in an ASCII comment switches it to UNICODE, as ExifTool\n // does, in the block's order; an existing UNICODE one keeps its order.\n const order =\n code === 'UNICODE'\n ? unicodeOrder(current.subarray(8), blockLittle)\n : { little: blockLittle, bom: false }\n const bom = order.bom ? (order.little ? [0xff, 0xfe] : [0xfe, 0xff]) : []\n return concat(\n encoder.encode('UNICODE\\0'),\n bom,\n encodeUcs2(text, order.little),\n )\n}\n\n/**\n * EXIF 2.32 §4.6.5 Copyright holds `photographer\\0editor\\0`. An edit\n * replaces the photographer's part and keeps the editor's; with only an\n * editor's part left the photographer's is one space, as the spec says.\n */\nfunction copyrightValue(\n current: Uint8Array | null,\n text: string | null,\n): Uint8Array | null {\n const raw = current ?? new Uint8Array()\n const nul = raw.indexOf(0)\n let editor = nul >= 0 ? raw.subarray(nul + 1) : new Uint8Array()\n const end = editor.indexOf(0)\n if (end >= 0) editor = editor.subarray(0, end)\n if (!decodeLegacyText(editor).trim()) {\n return text === null ? null : asciiValue(text)\n }\n return concat(encoder.encode(text ?? ' '), [0], editor, [0])\n}\n\n/**\n * Turn a canonical patch into writes of tags that ALREADY EXIST. A value\n * the file does not hold yet goes to XMP (the Metadata Working Group's\n * rule), which is the XMP writer's job, not this one's.\n */\nfunction planPatch(\n b: Uint8Array,\n tree: TiffTree,\n patch: EmbeddedPatch,\n): { writes: TiffTagWrite[]; scrubGps: boolean } {\n const little = tree.header.little\n const writes: TiffTagWrite[] = []\n const patched = (key: string) =>\n Object.prototype.hasOwnProperty.call(patch, key) && patch[key] !== undefined\n const entry = (ifd: TiffDirectory, tag: number) => entryOf(tree[ifd], tag)\n const put = (\n ifd: TiffDirectory,\n tag: number,\n type: number,\n value: Uint8Array | null | undefined,\n ) => {\n if (value !== undefined && entry(ifd, tag)) {\n writes.push({ ifd, tag, type, value })\n }\n }\n const ascii = (ifd: TiffDirectory, tag: number, text: string | null) =>\n put(ifd, tag, T.ASCII, text === null ? null : asciiValue(text))\n const xp = (tag: number, text: string | null) => {\n const type = entry('ifd0', tag)?.type === T.UNDEFINED ? T.UNDEFINED : T.BYTE\n put('ifd0', tag, type, text === null ? null : xpValue(text))\n }\n const text = (key: string, separator = ', ') =>\n patchText(patch[key], separator) ?? null\n\n for (const [key, tag] of IFD0_TEXT) {\n if (patched(key)) ascii('ifd0', tag, text(key))\n }\n if (patched('lens')) ascii('exif', TAG.lensModel, text('lens'))\n if (patched('creator')) {\n ascii('ifd0', TAG.artist, text('creator', '; '))\n xp(TAG.xpAuthor, text('creator', '; '))\n }\n if (patched('title')) xp(TAG.xpTitle, text('title'))\n if (patched('keywords')) xp(TAG.xpKeywords, text('keywords', ';'))\n if (patched('comment')) {\n xp(TAG.xpComment, text('comment'))\n const current = valueBytes(b, entry('exif', TAG.userComment))\n put(\n 'exif',\n TAG.userComment,\n T.UNDEFINED,\n userCommentValue(current, text('comment'), little),\n )\n }\n if (patched('copyright')) {\n const current = valueBytes(b, entry('ifd0', TAG.copyright))\n put(\n 'ifd0',\n TAG.copyright,\n T.ASCII,\n copyrightValue(current, text('copyright')),\n )\n }\n if (patched('createdAt')) {\n const raw = patch['createdAt']\n const iso = typeof raw === 'string' ? ISO_DATE.exec(raw.trim()) : null\n if (raw === null || iso) {\n const [, year, month, day, hour, minute, second, zone] = iso ?? []\n // A date without a time keeps the time blank-filled, the spec's way\n // of saying \"unknown\", rather than inventing midnight.\n const value = iso\n ? hour\n ? `${year}:${month}:${day} ${hour}:${minute}:${second ?? '00'}`\n : `${year}:${month}:${day} : : `\n : null\n ascii('exif', TAG.dateTimeOriginal, value)\n if (entry('exif', TAG.dateTimeOriginal)) {\n // The offset belongs to the old time; a new time without a zone\n // leaves it blank-filled (\"unknown\") rather than wrong.\n const offset =\n zone && hour ? (zone === 'Z' ? '+00:00' : zone) : ' : '\n ascii('exif', TAG.offsetTimeOriginal, value === null ? null : offset)\n }\n }\n }\n return {\n writes,\n scrubGps:\n Object.prototype.hasOwnProperty.call(patch, 'gps') &&\n patch['gps'] === null,\n }\n}\n\n/** A tag in the model of one IFD being edited. */\ninterface Slot {\n tag: number\n type: number\n count: number\n /** The 4-byte value-or-offset field, in the block's byte order. */\n field: Uint8Array\n /** The entry the slot was read from; null for an added tag. */\n from: TiffEntry | null\n dirty: boolean\n}\n\ninterface Dir {\n ifd: TiffIfd\n slots: Slot[]\n /** An entry was added or removed, so the table moves to the end. */\n moved: boolean\n}\n\n/** A span of the block and the structure that owns it. */\ninterface Claim {\n start: number\n end: number\n owner: object\n}\n\nconst HEADER_OWNER = { owner: 'header' }\nconst DATA_OWNER = { owner: 'data' }\n\nconst POINTER_TAG: Record<'exif' | 'gps', number> = {\n exif: TAG.exifIfd,\n gps: TAG.gpsIfd,\n}\n\nclass TiffEditor {\n private readonly source: Uint8Array\n private readonly work: Uint8Array\n private readonly little: boolean\n private readonly claims: Claim[]\n private readonly tail: Array<{ at: number; bytes: Uint8Array }> = []\n private end: number\n private changed = false\n private readonly ifd0: Dir\n private readonly subs: Partial<Record<'exif' | 'gps', Dir>> = {}\n private readonly gpsIfd: TiffIfd | null\n\n constructor(source: Uint8Array, tree: TiffTree, ifd0: TiffIfd) {\n this.source = source\n this.work = source.slice()\n this.end = source.length\n this.little = tree.header.little\n this.claims = claimMap(source, tree)\n this.gpsIfd = tree.gps\n this.ifd0 = this.dir(ifd0)\n if (tree.exif) this.subs.exif = this.dir(tree.exif)\n if (tree.gps) this.subs.gps = this.dir(tree.gps)\n }\n\n private dir(ifd: TiffIfd): Dir {\n return {\n ifd,\n moved: false,\n slots: ifd.entries.map((e) => ({\n tag: e.tag,\n type: e.type,\n count: e.count,\n field: this.source.slice(e.at + 8, e.at + 12),\n from: e,\n dirty: false,\n })),\n }\n }\n\n private directory(kind: TiffDirectory): Dir | undefined {\n return kind === 'ifd0' ? this.ifd0 : this.subs[kind]\n }\n\n /** Whether no structure outside `owners` claims any byte of the span. */\n private exclusive(start: number, end: number, owners: ReadonlySet<object>) {\n for (const claim of this.claims) {\n if (claim.start < end && start < claim.end && !owners.has(claim.owner)) {\n return false\n }\n }\n return true\n }\n\n /** The out-of-line bytes of an entry that lie inside the block. */\n private range(e: TiffEntry | null): [number, number] | null {\n if (!e || e.inline || e.size <= 0 || e.valueAt >= this.source.length) {\n return null\n }\n return [e.valueAt, Math.min(e.valueAt + e.size, this.source.length)]\n }\n\n private zero(start: number, end: number) {\n const from = Math.max(0, start)\n const to = Math.min(end, this.work.length)\n if (to > from) {\n this.work.fill(0, from, to)\n this.changed = true\n }\n }\n\n /** Zero an entry's old out-of-line value, unless something shares it. */\n private release(e: TiffEntry | null) {\n const range = this.range(e)\n if (e && range && this.exclusive(range[0], range[1], new Set([e]))) {\n this.zero(range[0], range[1])\n }\n }\n\n /** Append at the next even offset (TIFF 6.0 §2: offsets are word-aligned). */\n private append(bytes: Uint8Array): number {\n if (this.end % 2) this.end += 1\n const at = this.end\n this.tail.push({ at, bytes })\n this.end += bytes.length\n this.changed = true\n return at\n }\n\n /** Put a value where it may go and return the entry's 4-byte field. */\n private place(from: TiffEntry | null, bytes: Uint8Array): Uint8Array {\n if (bytes.length <= 4) {\n this.release(from)\n const field = new Uint8Array(4)\n field.set(bytes)\n return field\n }\n const range = this.range(from)\n if (\n from?.ok &&\n range &&\n bytes.length <= from.size &&\n this.exclusive(range[0], range[1], new Set([from]))\n ) {\n this.work.set(bytes, from.valueAt)\n this.work.fill(0, from.valueAt + bytes.length, from.valueAt + from.size)\n this.changed = true\n return encode32(from.valueAt, this.little)\n }\n this.release(from)\n return encode32(this.append(bytes), this.little)\n }\n\n private move(dir: Dir) {\n if (dir.moved) return\n if (\n !this.exclusive(\n dir.ifd.at,\n dir.ifd.at + dir.ifd.length,\n new Set([dir.ifd]),\n )\n ) {\n throw new EmbeddedWriteError(\n 'This file’s EXIF directories overlap other data, so they cannot be edited safely.',\n )\n }\n dir.moved = true\n this.changed = true\n }\n\n set(write: TiffTagWrite, allowAdd: boolean) {\n const dir = this.directory(write.ifd)\n const slot = dir?.slots.find((s) => s.tag === write.tag)\n if (write.value === null) {\n if (!dir || !slot) return\n this.move(dir)\n dir.slots = dir.slots.filter((s) => s !== slot)\n this.release(slot.from)\n return\n }\n const count =\n write.count ?? write.value.length / (TYPE_SIZE[write.type] ?? 1)\n if (!slot) {\n if (!allowAdd) return\n if (!dir) {\n throw new EmbeddedWriteError(\n `This file has no ${write.ifd === 'gps' ? 'GPS' : 'Exif'} directory to add a tag to.`,\n )\n }\n if (dir.slots.length >= 0xffff) {\n throw new EmbeddedWriteError('This file’s EXIF directory is full.')\n }\n this.move(dir)\n const field = this.place(null, write.value)\n dir.slots.push({\n tag: write.tag,\n type: write.type,\n count,\n field,\n from: null,\n dirty: true,\n })\n return\n }\n const current = valueBytes(this.source, slot.from ?? undefined)\n if (\n slot.type === write.type &&\n slot.count === count &&\n current &&\n sameBytes(current, write.value)\n ) {\n return\n }\n slot.field = this.place(slot.from, write.value)\n slot.type = write.type\n slot.count = count\n slot.dirty = true\n this.changed = true\n }\n\n /**\n * Remove the GPS IFD entirely: zero its table and every out-of-line value\n * it holds, then drop IFD0's pointer to it. Unreferencing it would leave\n * the coordinates in the file for anyone with a hex editor.\n */\n scrubGps() {\n const pointer = this.ifd0.slots.find((s) => s.tag === TAG.gpsIfd)\n if (!pointer) return\n const gps = this.gpsIfd\n if (!gps) {\n // A pointer to nothing (0, or past the end) holds no location, and is\n // simply dropped. One into the block that did not read as an IFD, or\n // reached an IFD already walked, may hide coordinates: refuse.\n const from = pointer.from\n const target =\n from?.inline && from.size === 4\n ? get32(this.source, from.valueAt, this.little)\n : -1\n if (target !== 0 && target < this.source.length) {\n throw new EmbeddedWriteError(\n 'This file’s location data is damaged, so it cannot be removed safely.',\n )\n }\n this.move(this.ifd0)\n this.ifd0.slots = this.ifd0.slots.filter((s) => s !== pointer)\n return\n }\n const owners = new Set<object>([gps, ...gps.entries])\n const spans: Array<[number, number]> = [[gps.at, gps.at + gps.length]]\n for (const e of gps.entries) {\n const range = this.range(e)\n if (range) spans.push(range)\n }\n for (const [start, end] of spans) {\n if (!this.exclusive(start, end, owners)) {\n throw new EmbeddedWriteError(\n 'This file’s location data shares its bytes with other data, so it cannot be removed safely.',\n )\n }\n }\n this.move(this.ifd0)\n for (const [start, end] of spans) this.zero(start, end)\n this.ifd0.slots = this.ifd0.slots.filter((s) => s !== pointer)\n delete this.subs.gps\n }\n\n private entryBytes(slot: Slot): Uint8Array {\n const out = new Uint8Array(12)\n put16(out, 0, slot.tag, this.little)\n put16(out, 2, slot.type, this.little)\n put32(out, 4, slot.count, this.little)\n out.set(slot.field, 8)\n return out\n }\n\n /** Write a fresh copy of the IFD at the end and zero the old table. */\n private relocate(dir: Dir): number {\n const slots = [...dir.slots].sort((a, b) => a.tag - b.tag)\n const table = new Uint8Array(2 + slots.length * 12 + 4)\n put16(table, 0, slots.length, this.little)\n slots.forEach((slot, i) => table.set(this.entryBytes(slot), 2 + i * 12))\n put32(table, 2 + slots.length * 12, dir.ifd.next, this.little)\n const at = this.append(table)\n this.zero(dir.ifd.at, dir.ifd.at + dir.ifd.length)\n return at\n }\n\n finish(maxLength: number | undefined): Uint8Array {\n for (const kind of ['exif', 'gps'] as const) {\n const dir = this.subs[kind]\n if (!dir?.moved) continue\n const at = this.relocate(dir)\n const pointer = this.ifd0.slots.find((s) => s.tag === POINTER_TAG[kind])\n if (pointer) {\n pointer.field = encode32(at, this.little)\n pointer.dirty = true\n }\n }\n if (this.ifd0.moved)\n put32(this.work, 4, this.relocate(this.ifd0), this.little)\n for (const dir of [this.ifd0, this.subs.exif, this.subs.gps]) {\n if (!dir || dir.moved) continue\n for (const slot of dir.slots) {\n if (slot.dirty && slot.from)\n this.work.set(this.entryBytes(slot), slot.from.at)\n }\n }\n if (!this.changed) return this.source\n if (maxLength !== undefined && this.end > maxLength) {\n throw new EmbeddedWriteError(\n `This edit would make the file’s EXIF block larger than the ${maxLength} bytes it can hold.`,\n )\n }\n if (this.end > 0xffffffff) {\n throw new EmbeddedWriteError(\n 'This edit would make the file larger than 4 GB.',\n )\n }\n const out = new Uint8Array(this.end)\n out.set(this.work)\n for (const { at, bytes } of this.tail) out.set(bytes, at)\n return out\n }\n}\n\n/** Every span of the block some known structure owns. */\nfunction claimMap(b: Uint8Array, tree: TiffTree): Claim[] {\n const claims: Claim[] = [{ start: 0, end: 8, owner: HEADER_OWNER }]\n const h = tree.header\n for (const ifd of tree.all) {\n claims.push({ start: ifd.at, end: ifd.at + ifd.length, owner: ifd })\n for (const e of ifd.entries) {\n if (!e.inline && e.size > 0 && e.valueAt < b.length) {\n claims.push({\n start: e.valueAt,\n end: Math.min(e.valueAt + e.size, b.length),\n owner: e,\n })\n }\n }\n for (const [offsetTag, lengthTag] of DATA_PAIRS) {\n const offsets = entryOf(ifd, offsetTag)\n const lengths = entryOf(ifd, lengthTag)\n if (!offsets || !lengths) continue\n const n = Math.min(offsets.count, lengths.count)\n let low = Infinity\n let high = 0\n for (let i = 0; i < n; i++) {\n const start = uintAt(b, h, offsets, i)\n const size = uintAt(b, h, lengths, i)\n if (start === null || size === null) break\n if (i < MAX_DATA_RANGES) {\n claims.push({ start, end: start + size, owner: DATA_OWNER })\n } else {\n low = Math.min(low, start)\n high = Math.max(high, start + size)\n }\n }\n // Past the cap the rest is claimed as one envelope: conservative,\n // since a claimed span is only ever left alone.\n if (high > low) claims.push({ start: low, end: high, owner: DATA_OWNER })\n }\n }\n return claims\n}\n\nfunction validateWrite(write: TiffTagWrite) {\n if (!['ifd0', 'exif', 'gps'].includes(write.ifd)) {\n throw new EmbeddedWriteError(`There is no ${String(write.ifd)} directory.`)\n }\n if (!Number.isInteger(write.tag) || write.tag < 0 || write.tag > 0xffff) {\n throw new EmbeddedWriteError(`Tag ${write.tag} is not a TIFF tag number.`)\n }\n if (write.ifd !== 'gps' && STRUCTURAL_TAGS.has(write.tag)) {\n throw new EmbeddedWriteError(\n `Tag 0x${write.tag.toString(16)} locates other data in the file and cannot be edited.`,\n )\n }\n if (write.value === null) return\n const unit = TYPE_SIZE[write.type]\n if (unit === undefined || write.type > T.IFD) {\n throw new EmbeddedWriteError(\n `TIFF field type ${write.type} cannot be written.`,\n )\n }\n const count = write.count ?? write.value.length / unit\n if (\n !write.value.length ||\n !Number.isInteger(count) ||\n count < 1 ||\n count > 0xffffffff ||\n count * unit !== write.value.length\n ) {\n throw new EmbeddedWriteError(\n `The value for tag 0x${write.tag.toString(16)} does not match its type and count.`,\n )\n }\n}\n\n/**\n * The one writer behind {@link writeExif}, {@link writeTiffTags} and the\n * TIFF file writer: a canonical patch and raw tag writes, in a single pass\n * so an IFD is relocated at most once. Returns `tiff` itself when nothing\n * needed to change. Throws {@link EmbeddedWriteError} when the block cannot\n * take the edit safely; it never returns a corrupt block.\n */\nexport function editTiff(tiff: Uint8Array, edit: TiffEdit): Uint8Array {\n const header = readHeader(tiff)\n if (!header) {\n throw new EmbeddedWriteError(\n 'The EXIF data in this file cannot be read, so it cannot be edited.',\n )\n }\n if (header.big) {\n throw new EmbeddedWriteError(\n 'Metadata in a BigTIFF file can be read here but not edited.',\n )\n }\n const tree = walk(tiff)\n if (!tree?.ifd0) {\n throw new EmbeddedWriteError(\n 'The EXIF data in this file is damaged, so it cannot be edited.',\n )\n }\n const plan = edit.patch\n ? planPatch(tiff, tree, edit.patch)\n : { writes: [], scrubGps: false }\n // One write per tag, the last one given.\n const latest = new Map<string, TiffTagWrite>()\n for (const write of [...plan.writes, ...(edit.writes ?? [])]) {\n validateWrite(write)\n const key = `${write.ifd}:${write.tag}`\n latest.delete(key)\n latest.set(key, write)\n }\n const editor = new TiffEditor(tiff, tree, tree.ifd0)\n if (plan.scrubGps) editor.scrubGps()\n for (const write of latest.values()) editor.set(write, edit.allowAdd ?? false)\n return editor.finish(edit.maxLength)\n}\n\n/**\n * Write a canonical patch into the EXIF tags that ALREADY EXIST — see the\n * module doc for which keys map where — and ignore every key this block\n * does not hold. `null` removes the tag; `gps: null` scrubs the GPS IFD.\n * `maxLength` is the block's ceiling: 65527 inside a JPEG APP1.\n */\nexport function writeExif(\n tiff: Uint8Array,\n patch: EmbeddedPatch,\n options?: { maxLength?: number },\n): Uint8Array {\n return editTiff(tiff, { patch, maxLength: options?.maxLength })\n}\n\n/**\n * Set or remove raw tags. A tag that is absent is added only with\n * `allowAdd`, and is otherwise skipped; a removal of an absent tag is a\n * no-op. Tags that locate other data (strips, tiles, the thumbnail, the\n * Exif/GPS/Interop pointers, SubIFDs, the MakerNote) are refused.\n */\nexport function writeTiffTags(\n tiff: Uint8Array,\n writes: TiffTagWrite[],\n options?: { allowAdd?: boolean; maxLength?: number },\n): Uint8Array {\n return editTiff(tiff, {\n writes,\n allowAdd: options?.allowAdd,\n maxLength: options?.maxLength,\n })\n}\n"],"names":["EmbeddedWriteError","TIFF_TYPE","BYTE","ASCII","SHORT","LONG","RATIONAL","SBYTE","UNDEFINED","SSHORT","SLONG","SRATIONAL","FLOAT","DOUBLE","IFD","LONG8","SLONG8","IFD8","T","TYPE_SIZE","TAG","imageDescription","make","model","stripOffsets","orientation","stripByteCounts","software","dateTime","artist","tileOffsets","tileByteCounts","subIfds","jpegInterchangeFormat","jpegInterchangeFormatLength","copyright","exposureTime","fNumber","exifIfd","gpsIfd","iso","dateTimeOriginal","offsetTime","offsetTimeOriginal","flash","focalLength","makerNote","userComment","xpTitle","xpComment","xpAuthor","xpKeywords","interopIfd","lensModel","GPS","latitudeRef","latitude","longitudeRef","longitude","altitudeRef","altitude","STRUCTURAL_TAGS","Set","DATA_PAIRS","MAX_IFDS","MAX_DATA_RANGES","ORIENTATION","get16","b","at","little","x","y","get32","lo","hi","get64","put16","value","put32","Math","floor","encode32","out","Uint8Array","concat","parts","reduce","n","part","length","set","sameBytes","a","i","utf8Strict","TextDecoder","fatal","utf16le","encoder","TextEncoder","CP1252_HIGH","decodeLatin1","bytes","byte","String","fromCharCode","isUtf8","decode","decodeLegacyText","cleanText","nul","indexOf","subarray","trim","decodeUcs2","even","swapped","cleanUcs2","text","slice","encodeUcs2","charCodeAt","isAscii","asciiValue","encode","xpValue","splitList","items","split","map","item","kept","filter","Boolean","trimNumber","places","fixed","toFixed","includes","replace","readHeader","version","big","ifd0","isTiff","parseIfd","h","countSize","entrySize","pointerSize","headerSize","Number","isSafeInteger","entriesEnd","next","entries","e","type","count","field","unit","size","undefined","inline","valueAt","push","tag","ok","min","uintAt","index","rationalAt","num","den","walk","header","seen","all","visit","has","add","ifd","pointer","find","exif","gps","chain","subs","entryOf","valueBytes","exifDateToIso","raw","offset","m","exec","year","month","day","hour","minute","second","zone","z","formatExposure","seconds","isFinite","round","describeFlash","fired","mode","strobe","join","userCommentCode","code","unicodeOrder","body","blockLittle","bom","highFirst","highSecond","decodeUserComment","order","gpsCoordinate","ref","degrees","minutes","decimal","abs","hemisphere","charAt","toUpperCase","readInto","tree","key","Array","isArray","xp","numeric","lat","lon","below","metres","original","aperture","focal","modified","readExif","tiff","values","Map","source","editable","readTiffTagBytes","entry","ISO_DATE","IFD0_TEXT","patchText","separator","userCommentValue","current","copyrightValue","editor","end","planPatch","patch","writes","patched","Object","prototype","hasOwnProperty","call","put","ascii","scrubGps","HEADER_OWNER","owner","DATA_OWNER","POINTER_TAG","TiffEditor","dir","moved","slots","from","dirty","directory","kind","exclusive","start","owners","claim","claims","range","zero","max","to","work","fill","changed","release","append","tail","place","move","write","allowAdd","slot","s","target","spans","entryBytes","relocate","sort","table","forEach","finish","maxLength","claimMap","offsetTag","lengthTag","offsets","lengths","low","Infinity","high","validateWrite","isInteger","toString","editTiff","edit","plan","latest","delete","writeExif","options","writeTiffTags"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
* GIF metadata blocks — comments, XMP and an ICC profile — read-only
|
|
19
|
+
* (AGL-3331).
|
|
20
|
+
*
|
|
21
|
+
* A GIF (GIF89a specification) is a header, a logical screen descriptor
|
|
22
|
+
* with an optional global color table, then a run of blocks up to the
|
|
23
|
+
* `0x3B` trailer: image descriptors (`0x2C`) and extensions (`0x21` and a
|
|
24
|
+
* label). Every variable-length payload is a chain of sub-blocks, each a
|
|
25
|
+
* length byte and that many bytes, ended by a zero length.
|
|
26
|
+
*
|
|
27
|
+
* - Comment extensions (label `0xFE`, section 24) are free text.
|
|
28
|
+
* - XMP is an application extension named `XMP Data` with authentication
|
|
29
|
+
* code `XMP` (XMP Specification Part 3, 1.1.2). It breaks the sub-block
|
|
30
|
+
* rule on purpose: the packet is written as raw bytes, followed by a
|
|
31
|
+
* 258-byte "magic trailer" (`0x01`, then `0xFF` down to `0x00`, then the
|
|
32
|
+
* terminator) that lands any sub-block walker on the terminator. The
|
|
33
|
+
* packet is the bytes before that trailer.
|
|
34
|
+
* - An ICC profile is the application extension `ICCRGBG1` / `012`, in
|
|
35
|
+
* ordinary sub-blocks.
|
|
36
|
+
*
|
|
37
|
+
* GIF is not writable here (see `MEDIA_EMBEDDED_WRITABLE_FORMATS`).
|
|
38
|
+
*/
|
|
39
|
+
import { type ImageBlocks } from './image-blocks';
|
|
40
|
+
/**
|
|
41
|
+
* Reads the metadata blocks of a GIF. Returns `null` when the bytes are not
|
|
42
|
+
* a GIF; a truncated or malformed file yields what came before the damage.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readGifBlocks(bytes: Uint8Array): ImageBlocks | null;
|
|
@@ -0,0 +1,134 @@
|
|
|
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
|
+
* GIF metadata blocks — comments, XMP and an ICC profile — read-only
|
|
18
|
+
* (AGL-3331).
|
|
19
|
+
*
|
|
20
|
+
* A GIF (GIF89a specification) is a header, a logical screen descriptor
|
|
21
|
+
* with an optional global color table, then a run of blocks up to the
|
|
22
|
+
* `0x3B` trailer: image descriptors (`0x2C`) and extensions (`0x21` and a
|
|
23
|
+
* label). Every variable-length payload is a chain of sub-blocks, each a
|
|
24
|
+
* length byte and that many bytes, ended by a zero length.
|
|
25
|
+
*
|
|
26
|
+
* - Comment extensions (label `0xFE`, section 24) are free text.
|
|
27
|
+
* - XMP is an application extension named `XMP Data` with authentication
|
|
28
|
+
* code `XMP` (XMP Specification Part 3, 1.1.2). It breaks the sub-block
|
|
29
|
+
* rule on purpose: the packet is written as raw bytes, followed by a
|
|
30
|
+
* 258-byte "magic trailer" (`0x01`, then `0xFF` down to `0x00`, then the
|
|
31
|
+
* terminator) that lands any sub-block walker on the terminator. The
|
|
32
|
+
* packet is the bytes before that trailer.
|
|
33
|
+
* - An ICC profile is the application extension `ICCRGBG1` / `012`, in
|
|
34
|
+
* ordinary sub-blocks.
|
|
35
|
+
*
|
|
36
|
+
* GIF is not writable here (see `MEDIA_EMBEDDED_WRITABLE_FORMATS`).
|
|
37
|
+
*/ import { asciiBytes, bytesAt, concatBytes, decodeFreeText, indexOfBytes, trimNul, utf8Decode } from "./image-blocks.js";
|
|
38
|
+
const GIF87A = asciiBytes('GIF87a');
|
|
39
|
+
const GIF89A = asciiBytes('GIF89a');
|
|
40
|
+
const XMP_APP = asciiBytes('XMP DataXMP');
|
|
41
|
+
const ICC_APP = asciiBytes('ICCRGBG1012');
|
|
42
|
+
/** The start of the XMP magic trailer; XML text never holds `0xFF`. */ const XMP_TRAILER = Uint8Array.from([
|
|
43
|
+
0x01,
|
|
44
|
+
0xff,
|
|
45
|
+
0xfe,
|
|
46
|
+
0xfd
|
|
47
|
+
]);
|
|
48
|
+
const XMP_TRAILER_LENGTH = 258;
|
|
49
|
+
/** Block count past which the walk stops; every block moves forward. */ const MAX_BLOCKS = 1 << 20;
|
|
50
|
+
/** Comments kept; a file with more is not carrying captions. */ const MAX_COMMENTS = 256;
|
|
51
|
+
/**
|
|
52
|
+
* Follows a sub-block chain from `offset`. Returns the offset after its
|
|
53
|
+
* terminator and the payload bytes (when `collect` is set), or `end: -1`
|
|
54
|
+
* when the chain runs off the end of the file.
|
|
55
|
+
*/ function subBlocks(bytes, offset, collect) {
|
|
56
|
+
const parts = [];
|
|
57
|
+
let at = offset;
|
|
58
|
+
while(at < bytes.length){
|
|
59
|
+
var _bytes_at;
|
|
60
|
+
const size = (_bytes_at = bytes[at]) != null ? _bytes_at : 0;
|
|
61
|
+
if (size === 0) {
|
|
62
|
+
return {
|
|
63
|
+
end: at + 1,
|
|
64
|
+
data: collect ? concatBytes(parts) : new Uint8Array(0)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (collect) {
|
|
68
|
+
parts.push(bytes.subarray(at + 1, Math.min(bytes.length, at + 1 + size)));
|
|
69
|
+
}
|
|
70
|
+
at += 1 + size;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
end: -1,
|
|
74
|
+
data: collect ? concatBytes(parts) : new Uint8Array(0)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** The size in bytes of a color table from a packed-fields byte. */ function colorTableSize(packed) {
|
|
78
|
+
return packed & 0x80 ? 3 * (1 << (packed & 0x07) + 1) : 0;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Reads the metadata blocks of a GIF. Returns `null` when the bytes are not
|
|
82
|
+
* a GIF; a truncated or malformed file yields what came before the damage.
|
|
83
|
+
*/ export function readGifBlocks(bytes) {
|
|
84
|
+
var _bytes_;
|
|
85
|
+
if (!bytesAt(bytes, 0, GIF89A) && !bytesAt(bytes, 0, GIF87A)) return null;
|
|
86
|
+
const blocks = {};
|
|
87
|
+
const comments = [];
|
|
88
|
+
// Header (6) + logical screen descriptor (7), then the global color table.
|
|
89
|
+
let offset = 13 + colorTableSize((_bytes_ = bytes[10]) != null ? _bytes_ : 0);
|
|
90
|
+
for(let count = 0; count < MAX_BLOCKS && offset < bytes.length; count += 1){
|
|
91
|
+
const introducer = bytes[offset];
|
|
92
|
+
if (introducer === 0x2c) {
|
|
93
|
+
var _bytes_1;
|
|
94
|
+
// Image descriptor (10 bytes), local color table, LZW code size, data.
|
|
95
|
+
if (offset + 10 > bytes.length) break;
|
|
96
|
+
offset += 10 + colorTableSize((_bytes_1 = bytes[offset + 9]) != null ? _bytes_1 : 0) + 1;
|
|
97
|
+
offset = subBlocks(bytes, offset, false).end;
|
|
98
|
+
if (offset < 0) break;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (introducer !== 0x21) break;
|
|
102
|
+
const label = bytes[offset + 1];
|
|
103
|
+
const start = offset + 2;
|
|
104
|
+
if (label === 0xfe) {
|
|
105
|
+
const { end, data } = subBlocks(bytes, start, true);
|
|
106
|
+
if (data.length && comments.length < MAX_COMMENTS) {
|
|
107
|
+
comments.push(trimNul(decodeFreeText(data)));
|
|
108
|
+
}
|
|
109
|
+
offset = end;
|
|
110
|
+
} else if (label === 0xff && bytes[start] === 11 && bytesAt(bytes, start + 1, XMP_APP)) {
|
|
111
|
+
const packetStart = start + 12;
|
|
112
|
+
const trailer = indexOfBytes(bytes, XMP_TRAILER, packetStart);
|
|
113
|
+
if (trailer >= 0 && blocks.xmp === undefined) {
|
|
114
|
+
blocks.xmp = trimNul(utf8Decode(bytes.subarray(packetStart, trailer)));
|
|
115
|
+
}
|
|
116
|
+
// The trailer makes the sub-block walk land on the terminator.
|
|
117
|
+
offset = subBlocks(bytes, start, false).end;
|
|
118
|
+
if (offset < 0 && trailer >= 0 && trailer + XMP_TRAILER_LENGTH <= bytes.length) {
|
|
119
|
+
offset = trailer + XMP_TRAILER_LENGTH;
|
|
120
|
+
}
|
|
121
|
+
} else if (label === 0xff && bytes[start] === 11 && bytesAt(bytes, start + 1, ICC_APP)) {
|
|
122
|
+
const { end, data } = subBlocks(bytes, start + 12, true);
|
|
123
|
+
if (end > 0 && data.length && !blocks.icc) blocks.icc = data;
|
|
124
|
+
offset = end;
|
|
125
|
+
} else {
|
|
126
|
+
offset = subBlocks(bytes, start, false).end;
|
|
127
|
+
}
|
|
128
|
+
if (offset < 0) break;
|
|
129
|
+
}
|
|
130
|
+
if (comments.length) blocks.comments = comments;
|
|
131
|
+
return blocks;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
//# sourceMappingURL=gif.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/aglyn/src/lib/app-utils/media-embedded-metadata/gif.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 * GIF metadata blocks — comments, XMP and an ICC profile — read-only\n * (AGL-3331).\n *\n * A GIF (GIF89a specification) is a header, a logical screen descriptor\n * with an optional global color table, then a run of blocks up to the\n * `0x3B` trailer: image descriptors (`0x2C`) and extensions (`0x21` and a\n * label). Every variable-length payload is a chain of sub-blocks, each a\n * length byte and that many bytes, ended by a zero length.\n *\n * - Comment extensions (label `0xFE`, section 24) are free text.\n * - XMP is an application extension named `XMP Data` with authentication\n * code `XMP` (XMP Specification Part 3, 1.1.2). It breaks the sub-block\n * rule on purpose: the packet is written as raw bytes, followed by a\n * 258-byte \"magic trailer\" (`0x01`, then `0xFF` down to `0x00`, then the\n * terminator) that lands any sub-block walker on the terminator. The\n * packet is the bytes before that trailer.\n * - An ICC profile is the application extension `ICCRGBG1` / `012`, in\n * ordinary sub-blocks.\n *\n * GIF is not writable here (see `MEDIA_EMBEDDED_WRITABLE_FORMATS`).\n */\n\nimport {\n asciiBytes,\n bytesAt,\n concatBytes,\n decodeFreeText,\n indexOfBytes,\n trimNul,\n utf8Decode,\n type ImageBlocks,\n} from './image-blocks'\n\nconst GIF87A = asciiBytes('GIF87a')\nconst GIF89A = asciiBytes('GIF89a')\nconst XMP_APP = asciiBytes('XMP DataXMP')\nconst ICC_APP = asciiBytes('ICCRGBG1012')\n/** The start of the XMP magic trailer; XML text never holds `0xFF`. */\nconst XMP_TRAILER = Uint8Array.from([0x01, 0xff, 0xfe, 0xfd])\nconst XMP_TRAILER_LENGTH = 258\n\n/** Block count past which the walk stops; every block moves forward. */\nconst MAX_BLOCKS = 1 << 20\n/** Comments kept; a file with more is not carrying captions. */\nconst MAX_COMMENTS = 256\n\n/**\n * Follows a sub-block chain from `offset`. Returns the offset after its\n * terminator and the payload bytes (when `collect` is set), or `end: -1`\n * when the chain runs off the end of the file.\n */\nfunction subBlocks(\n bytes: Uint8Array,\n offset: number,\n collect: boolean,\n): { end: number; data: Uint8Array } {\n const parts: Uint8Array[] = []\n let at = offset\n while (at < bytes.length) {\n const size = bytes[at] ?? 0\n if (size === 0) {\n return {\n end: at + 1,\n data: collect ? concatBytes(parts) : new Uint8Array(0),\n }\n }\n if (collect) {\n parts.push(bytes.subarray(at + 1, Math.min(bytes.length, at + 1 + size)))\n }\n at += 1 + size\n }\n return { end: -1, data: collect ? concatBytes(parts) : new Uint8Array(0) }\n}\n\n/** The size in bytes of a color table from a packed-fields byte. */\nfunction colorTableSize(packed: number): number {\n return packed & 0x80 ? 3 * (1 << ((packed & 0x07) + 1)) : 0\n}\n\n/**\n * Reads the metadata blocks of a GIF. Returns `null` when the bytes are not\n * a GIF; a truncated or malformed file yields what came before the damage.\n */\nexport function readGifBlocks(bytes: Uint8Array): ImageBlocks | null {\n if (!bytesAt(bytes, 0, GIF89A) && !bytesAt(bytes, 0, GIF87A)) return null\n const blocks: ImageBlocks = {}\n const comments: string[] = []\n // Header (6) + logical screen descriptor (7), then the global color table.\n let offset = 13 + colorTableSize(bytes[10] ?? 0)\n for (let count = 0; count < MAX_BLOCKS && offset < bytes.length; count += 1) {\n const introducer = bytes[offset]\n if (introducer === 0x2c) {\n // Image descriptor (10 bytes), local color table, LZW code size, data.\n if (offset + 10 > bytes.length) break\n offset += 10 + colorTableSize(bytes[offset + 9] ?? 0) + 1\n offset = subBlocks(bytes, offset, false).end\n if (offset < 0) break\n continue\n }\n if (introducer !== 0x21) break\n const label = bytes[offset + 1]\n const start = offset + 2\n if (label === 0xfe) {\n const { end, data } = subBlocks(bytes, start, true)\n if (data.length && comments.length < MAX_COMMENTS) {\n comments.push(trimNul(decodeFreeText(data)))\n }\n offset = end\n } else if (\n label === 0xff &&\n bytes[start] === 11 &&\n bytesAt(bytes, start + 1, XMP_APP)\n ) {\n const packetStart = start + 12\n const trailer = indexOfBytes(bytes, XMP_TRAILER, packetStart)\n if (trailer >= 0 && blocks.xmp === undefined) {\n blocks.xmp = trimNul(utf8Decode(bytes.subarray(packetStart, trailer)))\n }\n // The trailer makes the sub-block walk land on the terminator.\n offset = subBlocks(bytes, start, false).end\n if (\n offset < 0 &&\n trailer >= 0 &&\n trailer + XMP_TRAILER_LENGTH <= bytes.length\n ) {\n offset = trailer + XMP_TRAILER_LENGTH\n }\n } else if (\n label === 0xff &&\n bytes[start] === 11 &&\n bytesAt(bytes, start + 1, ICC_APP)\n ) {\n const { end, data } = subBlocks(bytes, start + 12, true)\n if (end > 0 && data.length && !blocks.icc) blocks.icc = data\n offset = end\n } else {\n offset = subBlocks(bytes, start, false).end\n }\n if (offset < 0) break\n }\n if (comments.length) blocks.comments = comments\n return blocks\n}\n"],"names":["asciiBytes","bytesAt","concatBytes","decodeFreeText","indexOfBytes","trimNul","utf8Decode","GIF87A","GIF89A","XMP_APP","ICC_APP","XMP_TRAILER","Uint8Array","from","XMP_TRAILER_LENGTH","MAX_BLOCKS","MAX_COMMENTS","subBlocks","bytes","offset","collect","parts","at","length","size","end","data","push","subarray","Math","min","colorTableSize","packed","readGifBlocks","blocks","comments","count","introducer","label","start","packetStart","trailer","xmp","undefined","icc"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
import { type ImageBlocks } from './image-blocks';
|
|
18
|
+
/**
|
|
19
|
+
* Reads the metadata blocks of a HEIC, HEIF or AVIF image. Returns `null`
|
|
20
|
+
* when the bytes are not in the HEIF family (no `ftyp` with a HEIF brand);
|
|
21
|
+
* a malformed file yields what could be read.
|
|
22
|
+
*/
|
|
23
|
+
export declare function readHeifBlocks(bytes: Uint8Array): ImageBlocks | null;
|