Skip to content

Instantly share code, notes, and snippets.

@yepitschunked
Created October 19, 2016 22:25
Show Gist options
  • Save yepitschunked/9d2e73d9228f5a0b300d75babe2c3796 to your computer and use it in GitHub Desktop.
Save yepitschunked/9d2e73d9228f5a0b300d75babe2c3796 to your computer and use it in GitHub Desktop.
extract image orientation from exif
export function extractOrientation(imgBlob) {
// written based on https://www.media.mit.edu/pia/Research/deepview/exif.html
// the exif orientation values are pretty nonsensical.
const orientationValueToRotateDegrees = {
1: 0,
3: 180,
6: 90,
8: 270,
};
return new Promise((resolve) => {
const fileReader = new FileReader();
fileReader.onload = () => resolve(fileReader);
fileReader.readAsArrayBuffer(imgBlob);
})
.then((reader) => {
const dataView = new DataView(reader.result);
let cursor = 0;
// look for jpeg headers
if (dataView.getUint16(cursor) !== 0xFFD8) {
throw new Error('not a valid jpeg');
}
// advance past the jpeg header
cursor += 2;
while (cursor < dataView.byteLength - 1) { // we read two bytes at a time
if (dataView.getUint16(cursor) === 0xFFE1) { // look for exif header
cursor += 2; // advance past exif header
// read the size of exif
// NB: this includes the 2 bytes of the size field itself, so we have to subtract 2
const exifSize = dataView.getUint16(cursor) - 2;
cursor += 2; // advance past exif size field
// return a new dataview with the exif region
return new DataView(reader.result, cursor, exifSize);
}
cursor += 2;
}
throw new Error('could not find exif start tag');
})
.then((exifView) => {
let cursor = 0; // skip the Exif string header
if (exifView.getUint32(cursor) !== 0x45786966) { // ascii hex values of the string 'Exif'
throw new Error('could not find Exif header');
}
cursor += 4; // advance past the exif header
// Now determine the endianness of the tags by checking the 8 byte TIFF header
const littleEndian = exifView.getUint16(cursor) === 0x4949;
cursor += 8; // advance past the TIFF header
// Now sloppily search for the orientation tag id
while (cursor < exifView.byteLength - 1) {
if (exifView.getUint16(cursor, littleEndian) === 0x0112) {
// advance past 2 byte tag id + 2 bytes of tag data type + 4 bytes of tag value count
cursor += 8;
const orientation = exifView.getUint16(cursor, littleEndian);
const rotate = orientationValueToRotateDegrees[orientation] || 0;
return rotate;
}
cursor += 2;
}
throw new Error('no orientation defined');
})
.catch(() => 0); // default to 0 rotation
}
@hnq90
Copy link

hnq90 commented Apr 13, 2020

👍 @jeradg

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment