diff --git a/src/file-parsers/heif.mjs b/src/file-parsers/heif.mjs index 601770d..b9ca338 100644 --- a/src/file-parsers/heif.mjs +++ b/src/file-parsers/heif.mjs @@ -88,6 +88,7 @@ export class HeifFileParser extends IsoBmffParser { //await this.findThumb(meta) if (this.options.icc.enabled) await this.findIcc(meta) if (this.options.tiff.enabled) await this.findExif(meta) + if (this.options.xmp.enabled) await this.findXmp(meta) } async registerSegment(key, offset, length) { @@ -143,6 +144,22 @@ export class HeifFileParser extends IsoBmffParser { await this.registerSegment('tiff', exifOffset, exifLength) } + async findXmp(meta) { + let iinf = this.findBox(meta, 'iinf') + if (iinf === undefined) return + let iloc = this.findBox(meta, 'iloc') + if (iloc === undefined) return + let xmpLocId = this.findXmpLocIdInIinf(iinf) + let extent = this.findExtentInIloc(iloc, xmpLocId) + if (extent === undefined) return + let [xmpOffset, xmpLength] = extent + await this.file.ensureChunk(xmpOffset, xmpLength) + let extentContentShift = 4 + xmpOffset += extentContentShift + xmpLength -= extentContentShift + await this.registerSegment('xmp', xmpOffset, xmpLength) + } + findExifLocIdInIinf(box) { this.parseBoxFullHead(box) let offset = box.start @@ -163,6 +180,28 @@ export class HeifFileParser extends IsoBmffParser { } } + findXmpLocIdInIinf(box) { + this.parseBoxFullHead(box) + let offset = box.start + let count = this.file.getUint16(offset) + let infe, infeOffset, idSize, name + offset += 2 + while (count--) { + infe = this.parseBoxHead(offset) + this.parseBoxFullHead(infe) + infeOffset = infe.start + if (infe.version >= 2) { + idSize = infe.version === 3 ? 4 : 2 + const dataLength = infe.length - idSize - infe.start + infe.offset - 2 + name = this.file.getString(infeOffset + idSize + 2, dataLength - 1) + if (name === 'mime\0application/rdf+xml') { + return this.file.getUintBytes(infeOffset, idSize) + } + } + offset += infe.length + } + } + get8bits(offset) { let n = this.file.getUint8(offset) let n0 = n >> 4 diff --git a/test/fixtures/avif/IMG_20180725_163423-2.avif b/test/fixtures/avif/IMG_20180725_163423-2.avif new file mode 100644 index 0000000..b3e9b7a Binary files /dev/null and b/test/fixtures/avif/IMG_20180725_163423-2.avif differ diff --git a/test/formats/avif.spec.mjs b/test/formats/avif.spec.mjs index e69a696..2bf5606 100644 --- a/test/formats/avif.spec.mjs +++ b/test/formats/avif.spec.mjs @@ -6,7 +6,7 @@ import * as exifr from '../../src/bundles/full.mjs' // TODO describe('AVIF - AvifFileParser', () => { - const options = {tiff: true, icc: true, mergeOutput: false, translateKeys: false, translateValues: false, reviveValues: false} + const options = {tiff: true, icc: true, xmp: true, mergeOutput: false, translateKeys: false, translateValues: false, reviveValues: false} const MAKE = 271 const MODEL = 272 @@ -34,4 +34,11 @@ describe('AVIF - AvifFileParser', () => { assert.equal(output.icc[PROFILE], 'acsp') }) + it(`should extract XMP from fixture3`, async () => { + let input = await getFile('avif/IMG_20180725_163423-2.avif') + let output = await exifr.parse(input, options) + assert.exists(output.xmp, 'output should contain XMP') + assert.equal(output.xmp.CreatorTool, 'HDR+ 1.0.199571065z') + }) + }) \ No newline at end of file