Skip to content

Instantly share code, notes, and snippets.

@jdrzejb
Created August 12, 2020 09:27
Show Gist options
  • Save jdrzejb/d8920fdfa7e9ed964362e70937f73096 to your computer and use it in GitHub Desktop.
Save jdrzejb/d8920fdfa7e9ed964362e70937f73096 to your computer and use it in GitHub Desktop.
Get exit orientation from a file using JavaScript and TypeScript
enum Bytes {
JPGStartMarker = 0xffd8,
EXIFMarker = 0xffe1,
EXIFInfo = 0x45786966,
OrientationMarker = 0x0112,
Empty = 0xff00,
ExifAlignment = 0x4949
}
/**
* Checks given file for `orientation` exif value.
* More info: https://www.media.mit.edu/pia/Research/deepview/exif.html
*
* @param file File which exif is being checked
* @returns Promise<number> where number represents image orientation as explained below on capital letter F
1 2 3 4 5 6 7 8
██████ ██████ ██ ██ ██████████ ██ ██ ██████████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
████ ████ ████ ████ ██ ██████████ ██████████ ██
██ ██ ██ ██
██ ██ ██████ ██████
*/
export function calculateOrientation(file: File): Promise<number> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsArrayBuffer(file.slice(0, 64 * 1024));
reader.onerror = reject;
// https://stackoverflow.com/questions/35789498/new-typescript-1-8-4-build-error-build-property-result-does-not-exist-on-t
reader.onload = (event: any) => {
const view = new DataView(event.target.result);
if (view.getUint16(0, false) !== Bytes.JPGStartMarker) {
// skip if file does not start with JPG start marker. Probably not a jpg.
resolve(-2);
}
const length = view.byteLength;
let offset = 2;
while (offset < length) {
const marker = view.getUint16(offset, false);
offset += 2;
if (marker === Bytes.EXIFMarker) {
offset += 2;
if (view.getUint32(offset, false) !== Bytes.EXIFInfo) {
// no exif info found in exif marker.
resolve(-1);
}
// check for bytes align. Data can be stored at different addresses (Intel, Motorola standards), so we need to make sure to get correct one.
const little = view.getUint16((offset += 6), false) === Bytes.ExifAlignment;
offset += view.getUint32(offset + 4, little);
// Get the exif tags count and go through all the elements.
const exifTags = view.getUint16(offset, little);
offset += 2;
for (let i = 0; i < exifTags; i += 1) {
// Get the tag and check if its correct one.
const exifOffset = offset + i * 12;
if (view.getUint16(exifOffset, little) === Bytes.OrientationMarker) {
// we're only interested in value. Skip name and length markers.
resolve(view.getUint16(exifOffset + 8, little));
}
}
// eslint-disable-next-line no-bitwise
} else if ((marker & Bytes.Empty) !== Bytes.Empty) {
// Empty marker. Skipping.
break;
} else {
offset += view.getUint16(offset, false); // skip current marker if exif marker not found
}
}
resolve(-1);
};
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment