Created
August 12, 2020 09:27
-
-
Save jdrzejb/d8920fdfa7e9ed964362e70937f73096 to your computer and use it in GitHub Desktop.
Get exit orientation from a file using JavaScript and TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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