I’m trying to remove the exif from the webp to avoid inconsistent exif handling between browsers, it’s all about rotating photos depending on orientation
I have prepared a mechanism that will remove the exif based on the webp format specification
and https://github.com/MikeKovarik/exifr/pull/112/files
short idea:
- find exif chunk
- remove founded chunk
const fs = require("fs");
function myFn(buffer: ArrayBuffer) {
try {
const dv = new DataView(buffer);
const firstTwoBytes = dv.getUint16(0);
const isWep = firstTwoBytes === 0x5249 && dv.getUint32(0) === 0x52494646 && dv.getUint32(8) === 0x57454250;
if (!isWep) {
return;
}
let exifHead: number = null;
let exifLength: number = null;
const webpHeaderChunkOffset = 12;
let head = webpHeaderChunkOffset;
while (head + 8 <= buffer.byteLength) {
const chunkType = getString(buffer, head, 4);
const chunkLength = dv.getUint32(head + 4, true);
if (chunkType === "VP8X") {
const flag = dv.getUint8(head + 4 + 4);
const hasEXIF = !!((flag & (1 << 3)) >> 3);
if (!hasEXIF) {
break;
}
} else if (chunkType === "EXIF") {
exifHead = head;
exifLength = chunkLength + 8 + (chunkLength % 2);
break;
}
head += chunkLength + 8;
head += head % 2;
}
const newArrayBuffer =
exifHead !== null && exifLength !== null ? removeDataFromArrayBuffer(buffer, exifHead, exifLength) : buffer;
fs.writeFile("output_image.webp", Buffer.from(newArrayBuffer), (err) => {
if (err) {
console.error(err);
} else {
console.log("Saved");
}
});
console.log(exifHead, exifLength);
} catch (error) {
console.log(error);
}
}
function removeDataFromArrayBuffer(buffer: ArrayBuffer, start: number, length: number): ArrayBuffer {
const totalLength = buffer.byteLength;
const newLength = totalLength - length;
const newBuffer = new ArrayBuffer(newLength);
const originalArray = new Uint8Array(buffer);
const newArray = new Uint8Array(newBuffer);
if (start > 0) {
newArray.set(originalArray.subarray(0, start));
}
if (start + length < totalLength) {
newArray.set(originalArray.subarray(start + length, totalLength), start);
}
return newBuffer;
}
function getString(buffer: ArrayBuffer, offset: number, length: number): string {
let arr = getUint8Array(buffer, offset, length);
return Buffer.from(arr).toString("utf8");
}
function getUint8Array(buffer: ArrayBuffer, offset: number, length: number): Uint8Array {
return new Uint8Array(buffer, offset, length);
}
function readImageToBuffer(filePath): Promise<Buffer> {
return new Promise((resolve, reject) => {
fs.readFile(filePath, (err, data) => {
if (err) {
reject(err);
} else {
const arrayBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
resolve(arrayBuffer);
}
});
});
}
async function run() {
const filePath = "path/to/image.webp";
const buffer = await readImageToBuffer(filePath);
myFn(buffer);
}
run();
But after saving the photo with the deleted exif, the system shows me that the photo is corrupted. I think the exif I delete is correct found, what could be wrong?