exifr
Version:
📷 The fastest and most versatile JavaScript EXIF reading library.
61 lines (53 loc) • 2.27 kB
JavaScript
import {fileReaders} from '../plugins.mjs'
import {ChunkedReader} from './ChunkedReader.mjs'
import * as platform from '../util/platform.mjs'
import {Buffer} from '../util/platform.mjs'
export class Base64Reader extends ChunkedReader {
constructor(...args) {
super(...args)
// Remove the mime type and base64 marker at the beginning so that we're left off with clear b64 string.
this.input = this.input.replace(/^data:([^;]+);base64,/gmi, '')
this.size = (this.input.length / 4) * 3
if (this.input.endsWith('==')) this.size -= 2
else if (this.input.endsWith('=')) this.size -= 1
}
// Accepts base64 or base64 URL and converts it to DataView and trims if needed.
async _readChunk(offset, length) {
let base64 = this.input
// Base64 encodes 3 bytes of data into string of 4 characters.
// To extract bytes at certain offset and length we need to take that into account,
// recalculate the offset and length into blocks of 4 characters, slice the input base64 string
// from these first and last of these blocks, and finally adjust correct offset in these blocks.
// NOTE: Each 4 character block of base64 string represents 3 bytes of data.
let blockStart, offsetInBlock
if (offset === undefined) {
// Start from begining of the 4-letter block.
offset = 0
blockStart = 0
offsetInBlock = 0
} else {
// Adjust offset from the start of the 4-letter block.
blockStart = Math.floor(offset / 3) * 4
offsetInBlock = offset - ((blockStart / 4) * 3)
}
if (length === undefined) {
length = this.size
}
let end = offset + length
let blockEnd = blockStart + Math.ceil(end / 3) * 4
base64 = base64.slice(blockStart, blockEnd)
let clampedLength = Math.min(length, this.size - offset)
if (platform.hasBuffer) {
let slice = Buffer.from(base64, 'base64').slice(offsetInBlock, offsetInBlock + clampedLength)
return this.set(slice, offset, true)
} else {
let chunk = this.subarray(offset, clampedLength, true)
let binary = atob(base64)
let uint8view = chunk.toUint8()
for (let i = 0; i < clampedLength; i++)
uint8view[i] = binary.charCodeAt(offsetInBlock + i)
return chunk
}
}
}
fileReaders.set('base64', Base64Reader)