1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be 3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file. 4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvar exif = { 6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen verbose: false, 7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen messageHandlers: { 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "init": function() { 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.log('thumbnailer initialized'); 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "get-exif": function(fileURL) { 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.processOneFile(fileURL, function callback(metadata) { 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen postMessage({verb: 'give-exif', 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arguments: [fileURL, metadata]}); 17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }); 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen processOneFile: function(fileURL, callback) { 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var self = this; 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var currentStep = -1; 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen function nextStep(var_args) { 26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.vlog('nextStep: ' + steps[currentStep + 1].name); 27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen steps[++currentStep].apply(self, arguments); 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen function onError(err) { 31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.vlog('Error processing: ' + fileURL + ': step: ' + 32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen steps[currentStep].name + ": " + err); 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen postMessage({verb: 'give-exif-error', 35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arguments: [fileURL, steps[currentStep].name, err]}); 36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var steps = 39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen [ // Step one, turn the url into an entry. 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen function getEntry() { 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen webkitResolveLocalFileSystemURL(fileURL, 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen function(entry) { nextStep(entry) }, 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen onError); 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Step two, turn the entry into a file. 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen function getFile(entry) { 48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.file(function(file) { nextStep(file) }, onError); 49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Step three, read the file header into a byte array. 52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen function readHeader(file) { 53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var reader = new FileReader(file.webkitSlice(0, 1024)); 54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen reader.onerror = onError; 55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen reader.onload = function(event) { nextStep(file, reader.result) }; 56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen reader.readAsArrayBuffer(file); 57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Step four, find the exif marker and read all exif data. 60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen function findExif(file, buf) { 61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var br = new exif.BufferReader(buf); 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var mark = br.readMark(); 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (mark != exif.MARK_SOI) 64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return onError('Invalid file header: ' + mark.toString(16)); 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen while (true) { 67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (mark == exif.MARK_SOS || br.eof()) { 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return onError('Unable to find EXIF marker'); 69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen mark = br.readMark(); 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (mark == exif.MARK_EXIF) { 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var length = br.readMarkLength(); 74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Offsets inside the EXIF block are based after this bit of 76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // magic, so we verify and discard it here, before exif parsing, 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // to make offset calculations simpler. 78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var magic = br.readString(6); 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (magic != 'Exif\0\0') 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return onError('Invalid EXIF magic: ' + magic.toString(16)); 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var pos = br.tell(); 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var reader = new FileReader(); 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen reader.onerror = onError; 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen reader.onload = function(event) { nextStep(file, reader.result) }; 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen reader.readAsArrayBuffer(file.webkitSlice(pos, pos + length - 6)); 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen br.skipMarkData(); 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Step five, parse the exif data. 95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen function parseExif(file, buf) { 96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var br = new exif.BufferReader(buf); 97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var order = br.readScalar(2); 98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (order == exif.ALIGN_LITTLE) { 99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen br.setByteOrder(exif.BufferReader.LITTLE_ENDIAN); 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else if (order != exif.ALIGN_BIG) { 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return onError('Invalid alignment value: ' + order.toString(16)); 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var tag = br.readScalar(2); 105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (tag != exif.TAG_TIFF) 106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return onError('Invalid TIFF tag: ' + tag.toString(16)); 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var tags = {}; 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var directoryOffset = br.readScalar(4); 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen while (directoryOffset) { 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen br.seek(directoryOffset); 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var entryCount = br.readScalar(2); 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (var i = 0; i < entryCount; i++) { 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var tag = tags[br.readScalar(2)] = {}; 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tag.format = br.readScalar(2); 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tag.componentCount = br.readScalar(4); 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tag.value = br.readScalar(4); 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }; 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen directoryOffset = br.readScalar(4); 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var metadata = { rawTags: tags }; 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (exif.TAG_JPG_THUMB_OFFSET in tags && 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen exif.TAG_JPG_THUMB_LENGTH in tags) { 128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen br.seek(tags[exif.TAG_JPG_THUMB_OFFSET].value); 129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var b64 = br.readBase64(tags[exif.TAG_JPG_THUMB_LENGTH].value); 130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen metadata.thumbnailURL = 'data:image/jpeg;base64,' + b64; 131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.vlog('Image has EXIF data, but no JPG thumbnail.'); 133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (exif.TAG_EXIF_IMAGE_WIDTH in tags) 136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen metadata.exifImageWidth = tags[exif.TAG_IMAGE_WIDTH]; 137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (exif.TAG_EXIF_IMAGE_HEIGHT in tags) 139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen metadata.exifImageHeight = tags[exif.TAG_IMAGE_HEIGHT]; 140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen nextStep(metadata); 142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Step six, we're done. 145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen callback 146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ]; 147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen nextStep(); 149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen onMessage: function(event) { 152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var data = event.data; 153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (this.messageHandlers.hasOwnProperty(data.verb)) { 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen //this.log('dispatching: ' + data.verb + ': ' + data.arguments); 156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.messageHandlers[data.verb].apply(this, data.arguments); 157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.log('Unknown message from client: ' + data.verb, data); 159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen log: function(var_args) { 163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var ary = Array.apply(null, arguments); 164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen postMessage({verb: 'log', arguments: ary}); 165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen vlog: function(var_args) { 168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (this.verbose) 169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.log.apply(this, arguments); 170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.MARK_SOI = 0xffd8; // Start of image data. 174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.MARK_SOS = 0xffda; // Start of "stream" (the actual image data). 175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.MARK_EXIF = 0xffe1; // Start of exif block. 176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.ALIGN_LITTLE = 0x4949; // Indicates little endian alignment of exif data. 178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.ALIGN_BIG = 0x4d4d; // Indicates big endian alignment of exif data. 179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.TAG_TIFF = 0x002a; // First tag in the exif data. 181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.TAG_JPG_THUMB_OFFSET = 0x0201; 182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.TAG_JPG_THUMB_LENGTH = 0x0202; 183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.TAG_EXIF_IMAGE_WIDTH = 0xa002; 184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.TAG_EXIF_IMAGE_HEIGHT = 0xa003; 185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.BufferReader = function(buf) { 187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.buf_ = buf; 188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.ary_ = new Uint8Array(buf); 189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.pos_ = 0; 190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.setByteOrder(exif.BufferReader.BIG_ENDIAN); 191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.BufferReader.LITTLE_ENDIAN = 0; // Intel, 0x1234 is [0x34, 0x12] 194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.BufferReader.BIG_ENDIAN = 1; // Motorola, 0x002a is [0x12, 0x34] 195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenexif.BufferReader.prototype = { 197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen setByteOrder: function(order) { 198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.order_ = order; 199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (order == exif.BufferReader.LITTLE_ENDIAN) { 200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.readScalar = this.readLittle; 201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.readScalar = this.readBig; 203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen eof: function() { 207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return this.pos_ >= this.ary_.length; 208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen readScalar: null, // Either readLittle or readBig, according to byte order. 211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen /** 213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * Big endian read. Most significant bytes come first. 214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen */ 215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen readBig: function(width) { 216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var rv = 0; 217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen switch(width) { 218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case 4: 219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv = this.ary_[this.pos_++] << 24; 220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case 3: 221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv |= this.ary_[this.pos_++] << 16; 222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case 2: 223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv |= this.ary_[this.pos_++] << 8; 224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case 1: 225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv |= this.ary_[this.pos_++]; 226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return rv; 229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen /** 232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * Little endian read. Least significant bytes come first. 233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen */ 234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen readLittle: function(width) { 235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var rv = 0; 236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen switch(width) { 237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case 4: 238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv = this.ary_[this.pos_ + 3] << 24; 239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case 3: 240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv |= this.ary_[this.pos_ + 2] << 16; 241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case 2: 242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv |= this.ary_[this.pos_+ 1] << 8; 243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case 1: 244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv |= this.ary_[this.pos_]; 245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.pos_ += width; 248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return rv; 249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen readString: function(length) { 252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var chars = []; 253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (var i = 0; i < length; i++) { 254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen chars[i] = String.fromCharCode(this.ary_[this.pos_++]); 255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return chars.join(''); 258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base64Alphabet_: ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 'abcdefghijklmnopqrstuvwxyz' + 262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen '0123456789+/').split(''), 263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen readBase64: function(length) { 265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var rv = []; 266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var chars = []; 267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var padding = 0; 268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (var i = 0; i < length; /* incremented inside */) { 270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var bits = this.ary_[this.pos_ + i++] << 16; 271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (i < length) { 273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bits |= this.ary_[this.pos_ + i++] << 8; 274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (i < length) { 276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bits |= this.ary_[this.pos_ + i++]; 277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen padding = 1; 279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen padding = 2; 282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen chars[3] = this.base64Alphabet_[bits & 63]; 285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen chars[2] = this.base64Alphabet_[(bits >> 6) & 63]; 286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen chars[1] = this.base64Alphabet_[(bits >> 12) & 63]; 287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen chars[0] = this.base64Alphabet_[(bits >> 18) & 63]; 288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rv.push.apply(rv, chars); 290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.pos_ += i; 293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (padding > 0) 295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen chars[chars.length - 1] = '='; 296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (padding > 1) 297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen chars[chars.length - 2] = '='; 298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return rv.join(''); 300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen readMark: function() { 303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return this.readScalar(2); 304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen readMarkLength: function() { 307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Length includes the 2 bytes used to store the length. 308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return this.readScalar(2) - 2; 309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen readMarkData: function(opt_arrayConstructor) { 312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var arrayConstructor = opt_arrayConstructor || Uint8Array; 313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var length = this.readMarkLength(); 315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen var slice = new arrayConstructor(this.buf_, this.pos_, length); 316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.pos_ += length; 317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return slice; 319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen skipMarkData: function() { 322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.skip(this.readMarkLength()); 323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen seek: function(pos) { 326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.pos_ = pos; 327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen skip: function(count) { 330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this.pos_ += count; 331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen }, 332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tell: function() { 334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return this.pos_; 335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvar onmessage = exif.onMessage.bind(exif); 339