src/services/exifService.ts
const applicationSegmentOneMarker = 0xFFE1;
const beginOfExifHeaderMarker = 0x45786966;
const byteOrderMarker = 0x4949;
const byteStuffingMarker = 0xFF00;
const orientationMarker = 0x0112;
const startOfFileMarker = 0xFFD8;
const parseBytes = (dataView: DataView, resolve: (uint16: number) => void): void => {
let offset = 2;
while (offset < dataView.byteLength) {
const marker = dataView.getUint16(offset, false);
offset += 2;
if (marker === applicationSegmentOneMarker
&& dataView.getUint32(offset + 2, false) !== beginOfExifHeaderMarker) {
resolve(-1);
} else if (marker === applicationSegmentOneMarker) {
offset += 8;
const little = dataView.getUint16(offset, false) === byteOrderMarker;
offset += dataView.getUint32(offset + 4, little);
const tags = dataView.getUint16(offset, little);
offset += 2;
for (let i = 0; i < tags; i ++) {
if (dataView.getUint16(offset + (i * 12), little) === orientationMarker) {
resolve(dataView.getUint16(offset + (i * 12) + 8, little));
}
}
} else if ((marker & byteStuffingMarker) !== byteStuffingMarker) {
resolve(-1);
} else {
offset += dataView.getUint16(offset, false);
}
}
resolve(-1);
};
const determineOrientation = async (file: File|Blob): Promise<number> => {
return new Promise((resolve: (orientation: number) => void): void => {
try {
const reader = new FileReader();
reader.onload = (): void => {
const dataView = new DataView(reader.result as SharedArrayBuffer | ArrayBuffer);
if (dataView.getUint16(0, false) !== startOfFileMarker) {
resolve(-1);
}
parseBytes(dataView, resolve);
};
reader.readAsArrayBuffer(new Blob([file]).slice(0, 64 * 1024));
} catch (error) {
resolve(1);
}
});
};
export default {
determineOrientation,
};