Skip to content

Instantly share code, notes, and snippets.

@runeb
Created February 12, 2021 16:34
Show Gist options
  • Save runeb/29b3307cbf28b419f4add808a0d822c9 to your computer and use it in GitHub Desktop.
Save runeb/29b3307cbf28b419f4add808a0d822c9 to your computer and use it in GitHub Desktop.
// Exif orientation value to css transform mapping
type Rotation = string;
const rotations: Record<number, Rotation> = {
1: "rotate(0deg)",
2: "rotateY(180deg)",
3: "rotate(180deg)",
4: "rotate(180deg) rotateY(180deg)",
5: "rotate(270deg) rotateY(180deg)",
6: "rotate(90deg)",
7: "rotate(90deg) rotateY(180deg)",
8: "rotate(270deg)",
} as const;
function _arrayBufferToBase64(buffer) {
var binary = "";
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; ) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
function parseArrayBuffer(buffer: ArrayBuffer): Rotation | null {
var idx = 0;
var scanner = new DataView(buffer);
if (buffer.byteLength < 2 || scanner.getUint16(idx) != 0xffd8) {
// Not a JPEG
return;
}
idx += 2;
var value = 1; // Non-rotated is the default
var leftToRead = scanner.byteLength - idx;
var littleEndian = false;
function readUint16(offset = 0, advancePointer = true): number {
const n = scanner.getUint16(idx + offset, littleEndian);
if (advancePointer) {
idx += 2 + offset;
}
return n;
}
while (idx < leftToRead) {
var uint16 = readUint16();
idx += 2;
switch (uint16) {
case 0xffe1: // Start of EXIF
// II (0x4949) Indicates Intel format - Little Endian
// MM (0x4D4D) Indicates Motorola format - Big Endian
littleEndian = readUint16(8, false) === 0x4949;
var exifLength = readUint16();
leftToRead = exifLength - idx;
var exifLength = scanner.getUint16(idx, littleEndian);
maxBytes = exifLength - idx;
idx += 2;
break;
case 0x0112: // Orientation tag
// Read the value, its 6 bytes further out
// See page 102 at the following URL
// http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf
value = scanner.getUint16(idx + 6, false);
maxBytes = 0; // Stop scanning
break;
}
}
if (callback) {
callback(base64img, value);
}
}
export async function rotation(file: Blob): Promise<?Rotation> {
return new Promise((resolve) => {
var fileReader = new FileReader();
fileReader.onloadend = () => resolve(parseArrayBuffer(fileReader.result));
fileReader.readAsArrayBuffer(file);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment