Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WebP support #112

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/bundles/full.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import '../file-readers/Base64Reader.mjs'
import '../file-parsers/tiff.mjs'
import '../file-parsers/heif.mjs'
import '../file-parsers/png.mjs'
import '../file-parsers/webp.mjs'

// TIFF - Additional tags
import '../dicts/tiff-interop-keys.mjs'
Expand Down
68 changes: 68 additions & 0 deletions src/file-parsers/webp.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { FileParserBase } from '../parser.mjs'
import { fileParsers } from '../plugins.mjs'


export class WebpFileParser extends FileParserBase {

static type = 'webp'

static canHandle(file, firstTwoBytes) {
return firstTwoBytes === 0x5249
&& file.getUint32(0) === 0x52494646
&& file.getUint32(8) === 0x57454250
}

async parse() {
let { tiff, xmp, icc } = this.options

const chunks = {}
const hasChunks = { XMP: false, EXIF: false, ICC: false }

let head = 0x0C;
while (1) {
await this.file.ensureChunk(head, 8)
if (this.file.chunked && !this.file.available(head, 8) || head + 8 > this.file.byteLength)
break

const type = this.file.getString(head, 4)
const len = this.file.getUint32(head + 4, true)

if (type === "VP8X") {
await this.file.ensureChunk(head + 4 + 4, 1)
const flag = this.file.getUint8(head + 4 + 4, 1);
// hasChunks.ANIM = (flag & 1 << 1) >> 1
hasChunks.XMP = (flag & 1 << 2) >> 2 && xmp.enabled
hasChunks.EXIF = (flag & 1 << 3) >> 3 && tiff.enabled
// hasChunks.ALPHA = (flag & 1 << 4) >> 4
hasChunks.ICC = (flag & 1 << 5) >> 5 && icc.enabled
}

chunks[type.trim()] = { head: head + 8, len: len - 8 }

head += len + 8
head += head % 2

let foundAllChunks = true;
for (const key in hasChunks)
if (hasChunks[key] && !chunks[key])
foundAllChunks = false

if (foundAllChunks) break;
}

if (tiff.enabled && chunks.EXIF != undefined) {
await this.file.ensureChunk(chunks.EXIF.head, chunks.EXIF.len)
this.createParser('tiff', this.file.subarray(chunks.EXIF.head, chunks.EXIF.len))
}
if (xmp.enabled && chunks.XMP != undefined) {
await this.file.ensureChunk(chunks.XMP.head, chunks.XMP.len)
this.createParser('xmp', this.file.subarray(chunks.XMP.head, chunks.XMP.len))
}
if (icc.enabled && chunks.ICCP != undefined) {
await this.file.ensureChunk(chunks.ICCP.head, chunks.ICCP.len)
this.createParser('icc', this.file.subarray(chunks.ICCP.head, chunks.ICCP.len))
}
}
}

fileParsers.set('webp', WebpFileParser)
Binary file not shown.
Binary file not shown.
4 changes: 4 additions & 0 deletions test/formats/parser.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ describe('parser core', () => {
await exifr.parse(await getFile('avif/Irvine_CA.avif'))
})

it(`accepts WEBP`, async () => {
await exifr.parse(await getFile('webp/VRChat_2023-02-19_00-04-01.274_2160x3840.webp'))
})

})

})
36 changes: 36 additions & 0 deletions test/formats/webp.spec.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {assert} from '../test-util-core.mjs'
import {getFile} from '../test-util-core.mjs'
import * as exifr from '../../src/bundles/full.mjs'


describe('WEBP - WebpFileParser', () => {

const options = {xmp: true, tiff: true, icc: true, mergeOutput: false, translateKeys: false, translateValues: false, reviveValues: false}

const MAKE = 271
const MODEL = 272
const PROFILE = 36

it(`should extract TIFF from fixture1`, async () => {
let input = await getFile('webp/VRChat_2023-02-19_00-04-01.274_2160x3840.webp')
let output = await exifr.parse(input, options)
assert.exists(output.ifd0, 'output should contain IFD0')
assert.equal(output.ifd0[MAKE], 'logilabo')
assert.equal(output.ifd0[MODEL], 'VirtualLens2')
})

it(`should extract EXIF from fixture1`, async () => {
let input = await getFile('webp/VRChat_2023-02-19_00-04-01.274_2160x3840.webp')
let output = await exifr.parse(input, options)
assert.exists(output.exif, 'output should contain EXIF')
assert.isDefined(output.exif[36867])
})

it(`should extract ICC from fixture2`, async () => {
let input = await getFile('webp/VRChat_3840x2160_2022-09-04_22-48-26.551.webp')
let output = await exifr.parse(input, options)
assert.exists(output.icc, 'output should contain ICC')
assert.equal(output.icc[PROFILE], 'acsp')
})

})
1 change: 1 addition & 0 deletions test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import './formats/parser.spec.mjs'
import './formats/jpeg.spec.mjs'
import './formats/heic.spec.mjs'
import './formats/webp.spec.mjs'
import './formats/avif.spec.mjs'
import './formats/png.spec.mjs'
import './options.spec.mjs'
Expand Down