1
const IPTC_ENTRY_TYPES = new Map([
8
[0x7a, 'captionWriter'],
14
const IPTC_ENTRY_MARKER = Buffer.from([0x1c, 0x02]);
16
export function parseIptc(buffer: Buffer): Record<string, unknown> {
17
if (!Buffer.isBuffer(buffer)) return {};
19
const iptc: Record<string, any> = {};
20
let lastIptcEntryPos = buffer.indexOf(IPTC_ENTRY_MARKER);
22
while (lastIptcEntryPos !== -1) {
23
lastIptcEntryPos = buffer.indexOf(IPTC_ENTRY_MARKER, lastIptcEntryPos + IPTC_ENTRY_MARKER.byteLength);
25
const iptcBlockTypePos = lastIptcEntryPos + IPTC_ENTRY_MARKER.byteLength;
26
const iptcBlockSizePos = iptcBlockTypePos + 1;
27
const iptcBlockDataPos = iptcBlockSizePos + 2;
29
const iptcBlockType = buffer.readUInt8(iptcBlockTypePos);
30
const iptcBlockSize = buffer.readUInt16BE(iptcBlockSizePos);
32
if (!IPTC_ENTRY_TYPES.has(iptcBlockType)) {
36
const iptcBlockTypeId = IPTC_ENTRY_TYPES.get(iptcBlockType);
37
const iptcData = buffer.subarray(iptcBlockDataPos, iptcBlockDataPos + iptcBlockSize).toString();
39
if (iptcBlockTypeId) {
40
if (iptc[iptcBlockTypeId] == null) {
41
iptc[iptcBlockTypeId] = iptcData;
42
} else if (Array.isArray(iptc[iptcBlockTypeId])) {
43
iptc[iptcBlockTypeId].push(iptcData);
45
iptc[iptcBlockTypeId] = [iptc[iptcBlockTypeId], iptcData];
53
export function parseXmp(buffer: Buffer): Record<string, unknown> {
54
const xmp: Record<string, unknown> = {};
56
['title', 'description', 'rights', 'creator', 'subject'].forEach((x) => {
57
const tagRegex = new RegExp(`<dc:${x}>(.*?)</dc:${x}>`, 'smig'),
58
tagMatches = tagRegex.exec(buffer.toString());
60
if (!tagMatches || tagMatches.length === 0) {
64
const value = tagMatches[1]?.trim();
66
if (value?.toLowerCase().indexOf('<rdf:bag>') === 0) {
67
const r = new RegExp('<rdf:li>(.*?)</rdf:li>', 'smig');
68
let match = r.exec(value);
72
result.push(match[1]);
74
match = r.exec(value);
79
xmp[x] = value?.replace(/<[^>]*>?/gm, '').trim();