15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'use strict'; 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_MARK_SOI = 0xffd8; // Start of image data. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_MARK_SOS = 0xffda; // Start of "stream" (the actual image data). 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_MARK_SOF = 0xffc0; // Start of "frame" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_MARK_EXIF = 0xffe1; // Start of exif block. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_ALIGN_LITTLE = 0x4949; // Indicates little endian exif data. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_ALIGN_BIG = 0x4d4d; // Indicates big endian exif data. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_TIFF = 0x002a; // First directory containing TIFF data. 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_GPSDATA = 0x8825; // Pointer from TIFF to the GPS directory. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_EXIFDATA = 0x8769; // Pointer from TIFF to the EXIF IFD. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_SUBIFD = 0x014a; // Pointer from TIFF to "Extra" IFDs. 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_JPG_THUMB_OFFSET = 0x0201; // Pointer from TIFF to thumbnail. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_JPG_THUMB_LENGTH = 0x0202; // Length of thumbnail data. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_ORIENTATION = 0x0112; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_X_DIMENSION = 0xA002; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var EXIF_TAG_Y_DIMENSION = 0xA003; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function ExifParser(parent) { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageParser.call(this, parent, 'jpeg', /\.jpe?g$/i); 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype = {__proto__: ImageParser.prototype}; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {File} file // TODO(JSDOC). 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} metadata // TODO(JSDOC). 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function} callback // TODO(JSDOC). 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function} errorCallback // TODO(JSDOC). 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.parse = function(file, metadata, callback, errorCallback) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.requestSlice(file, callback, errorCallback, metadata, 0); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {File} file // TODO(JSDOC). 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function} callback // TODO(JSDOC). 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function} errorCallback // TODO(JSDOC). 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} metadata // TODO(JSDOC). 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} filePos // TODO(JSDOC). 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_length // TODO(JSDOC). 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.requestSlice = function( 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file, callback, errorCallback, metadata, filePos, opt_length) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read at least 1Kb so that we do not issue too many read requests. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opt_length = Math.max(1024, opt_length || 0); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = this; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var reader = new FileReader(); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader.onerror = errorCallback; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader.onload = function() { self.parseSlice( 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file, callback, errorCallback, metadata, filePos, reader.result); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader.readAsArrayBuffer(file.slice(filePos, filePos + opt_length)); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {File} file // TODO(JSDOC). 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function} callback // TODO(JSDOC). 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function} errorCallback // TODO(JSDOC). 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} metadata // TODO(JSDOC). 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} filePos // TODO(JSDOC). 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ArrayBuffer} buf // TODO(JSDOC). 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.parseSlice = function( 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file, callback, errorCallback, metadata, filePos, buf) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var br = new ByteReader(buf); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!br.canRead(4)) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We never ask for less than 4 bytes. This can only mean we reached EOF. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error('Unexpected EOF @' + (filePos + buf.byteLength)); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filePos == 0) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First slice, check for the SOI mark. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var firstMark = this.readMark(br); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (firstMark != EXIF_MARK_SOI) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error('Invalid file header: ' + firstMark.toString(16)); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = this; 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var reread = function(opt_offset, opt_bytes) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.requestSlice(file, callback, errorCallback, metadata, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filePos + br.tell() + (opt_offset || 0), opt_bytes); 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (true) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!br.canRead(4)) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cannot read the mark and the length, request a minimum-size slice. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reread(); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var mark = this.readMark(br); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mark == EXIF_MARK_SOS) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error('SOS marker found before SOF'); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var markLength = this.readMarkLength(br); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var nextSectionStart = br.tell() + markLength; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!br.canRead(markLength)) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the entire section. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filePos + br.tell() + markLength > file.size) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error( 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'Invalid section length @' + (filePos + br.tell() - 2)); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reread(-4, markLength + 4); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mark == EXIF_MARK_EXIF) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.parseExifSection(metadata, buf, br); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (ExifParser.isSOF_(mark)) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The most reliable size information is encoded in the SOF section. 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(1, ByteReader.SEEK_CUR); // Skip the precision byte. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var height = br.readScalar(2); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var width = br.readScalar(2); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExifParser.setImageSize(metadata, width, height); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback(metadata); // We are done! 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(nextSectionStart, ByteReader.SEEK_BEG); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (e) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errorCallback(e.toString()); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} mark // TODO(JSDOC). 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {boolean} // TODO(JSDOC). 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.isSOF_ = function(mark) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There are 13 variants of SOF fragment format distinguished by the last 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hex digit of the mark, but the part we want is always the same. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((mark & ~0xF) != EXIF_MARK_SOF) return false; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the last digit is 4, 8 or 12 it is not really a SOF. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var type = mark & 0xF; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (type != 4 && type != 8 && type != 12); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} metadata // TODO(JSDOC). 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ArrayBuffer} buf // TODO(JSDOC). 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ByteReader} br // TODO(JSDOC). 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.parseExifSection = function(metadata, buf, br) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var magic = br.readString(6); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (magic != 'Exif\0\0') { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some JPEG files may have sections marked with EXIF_MARK_EXIF 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but containing something else (e.g. XML text). Ignore such sections. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Invalid EXIF magic: ' + magic + br.readString(100)); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Offsets inside the EXIF block are based after the magic string. 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a new ByteReader based on the current position to make offset 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // calculations simpler. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br = new ByteReader(buf, br.tell()); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var order = br.readScalar(2); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (order == EXIF_ALIGN_LITTLE) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.setByteOrder(ByteReader.LITTLE_ENDIAN); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (order != EXIF_ALIGN_BIG) { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.log('Invalid alignment value: ' + order.toString(16)); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var tag = br.readScalar(2); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag != EXIF_TAG_TIFF) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.log('Invalid TIFF tag: ' + tag.toString(16)); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.littleEndian = (order == EXIF_ALIGN_LITTLE); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.ifd = { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) image: {}, 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thumbnail: {} 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var directoryOffset = br.readScalar(4); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Image directory. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Read image directory.'); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(directoryOffset); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) directoryOffset = this.readDirectory(br, metadata.ifd.image); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.imageTransform = this.parseOrientation(metadata.ifd.image); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Thumbnail Directory chained from the end of the image directory. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (directoryOffset) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Read thumbnail directory.'); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(directoryOffset); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.readDirectory(br, metadata.ifd.thumbnail); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If no thumbnail orientation is encoded, assume same orientation as 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the primary image. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.thumbnailTransform = 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.parseOrientation(metadata.ifd.thumbnail) || 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.imageTransform; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // EXIF Directory may be specified as a tag in the image directory. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (EXIF_TAG_EXIFDATA in metadata.ifd.image) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Read EXIF directory.'); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) directoryOffset = metadata.ifd.image[EXIF_TAG_EXIFDATA].value; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(directoryOffset); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.ifd.exif = {}; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.readDirectory(br, metadata.ifd.exif); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GPS Directory may also be linked from the image directory. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (EXIF_TAG_GPSDATA in metadata.ifd.image) { 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Read GPS directory.'); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) directoryOffset = metadata.ifd.image[EXIF_TAG_GPSDATA].value; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(directoryOffset); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.ifd.gps = {}; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.readDirectory(br, metadata.ifd.gps); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Thumbnail may be linked from the image directory. 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (EXIF_TAG_JPG_THUMB_OFFSET in metadata.ifd.thumbnail && 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXIF_TAG_JPG_THUMB_LENGTH in metadata.ifd.thumbnail) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Read thumbnail image.'); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(metadata.ifd.thumbnail[EXIF_TAG_JPG_THUMB_OFFSET].value); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.thumbnailURL = br.readImage( 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.ifd.thumbnail[EXIF_TAG_JPG_THUMB_LENGTH].value); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Image has EXIF data, but no JPG thumbnail.'); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} metadata // TODO(JSDOC). 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} width // TODO(JSDOC). 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} height // TODO(JSDOC). 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.setImageSize = function(metadata, width, height) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (metadata.imageTransform && metadata.imageTransform.rotate90) { 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.width = height; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.height = width; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.width = width; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.height = height; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ByteReader} br // TODO(JSDOC). 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {number} // TODO(JSDOC). 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.readMark = function(br) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return br.readScalar(2); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ByteReader} br // TODO(JSDOC). 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {number} // TODO(JSDOC). 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.readMarkLength = function(br) { 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Length includes the 2 bytes used to store the length. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return br.readScalar(2) - 2; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ByteReader} br // TODO(JSDOC). 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Array.<Object>} tags // TODO(JSDOC). 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {number} // TODO(JSDOC). 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.readDirectory = function(br, tags) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var entryCount = br.readScalar(2); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < entryCount; i++) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var tagId = br.readScalar(2); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var tag = tags[tagId] = {id: tagId}; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.format = br.readScalar(2); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.componentCount = br.readScalar(4); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.readTagValue(br, tag); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return br.readScalar(4); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ByteReader} br // TODO(JSDOC). 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} tag // TODO(JSDOC). 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.readTagValue = function(br, tag) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = this; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function safeRead(size, readFunction, signed) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsafeRead(size, readFunction, signed); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (ex) { 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.log('error reading tag 0x' + tag.id.toString(16) + '/' + 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.format + ', size ' + tag.componentCount + '*' + size + ' ' + 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (ex.stack || '<no stack>') + ': ' + ex); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value = null; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function unsafeRead(size, readFunction, signed) { 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!readFunction) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readFunction = function(size) { return br.readScalar(size, signed) }; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var totalSize = tag.componentCount * size; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (totalSize < 1) { 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is probably invalid exif data, skip it. 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.componentCount = 1; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value = br.readScalar(4); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (totalSize > 4) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the total size is > 4, the next 4 bytes will be a pointer to the 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // actual data. 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.pushSeek(br.readScalar(4)); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag.componentCount == 1) { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value = readFunction(size); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read multiple components into an array. 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value = []; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < tag.componentCount; i++) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value[i] = readFunction(size); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (totalSize > 4) { 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Go back to the previous position if we had to jump to the data. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.popSeek(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (totalSize < 4) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise, if the value wasn't exactly 4 bytes, skip over the 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unread data. 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(4 - totalSize, ByteReader.SEEK_CUR); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (tag.format) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 1: // Byte 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 7: // Undefined 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeRead(1); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 2: // String 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeRead(1); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag.componentCount == 0) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value = ''; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (tag.componentCount == 1) { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value = String.fromCharCode(tag.value); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value = String.fromCharCode.apply(null, tag.value); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 3: // Short 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeRead(2); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 4: // Long 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeRead(4); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 9: // Signed Long 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeRead(4, null, true); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 5: // Rational 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeRead(8, function() { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [br.readScalar(4), br.readScalar(4)]; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 10: // Signed Rational 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeRead(8, function() { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [br.readScalar(4, true), br.readScalar(4, true)]; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: // ??? 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Unknown tag format 0x' + Number(tag.id).toString(16) + 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ': ' + tag.format); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeRead(4); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('Read tag: 0x' + tag.id.toString(16) + '/' + tag.format + ': ' + 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag.value); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * TODO(JSDOC) 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {Array.<number>} 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.SCALEX = [1, -1, -1, 1, 1, 1, -1, -1]; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * TODO(JSDOC) 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {Array.<number>} 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.SCALEY = [1, 1, -1, -1, -1, 1, 1, -1]; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * TODO(JSDOC) 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {Array.<number>} 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.ROTATE90 = [0, 0, 0, 0, 1, 1, 1, 1]; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Transform exif-encoded orientation into a set of parameters compatible with 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * CSS and canvas transforms (scaleX, scaleY, rotation). 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} ifd exif property dictionary (image or thumbnail). 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {Object} // TODO(JSDOC). 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExifParser.prototype.parseOrientation = function(ifd) { 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifd[EXIF_TAG_ORIENTATION]) { 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var index = (ifd[EXIF_TAG_ORIENTATION].value || 1) - 1; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scaleX: ExifParser.SCALEX[index], 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scaleY: ExifParser.SCALEY[index], 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rotate90: ExifParser.ROTATE90[index] 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return null; 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MetadataDispatcher.registerParserClass(ExifParser); 440