| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 const EXIF_MARK_SOI = 0xffd8; // Start of image data. | 5 const EXIF_MARK_SOI = 0xffd8; // Start of image data. |
| 6 const EXIF_MARK_SOS = 0xffda; // Start of "stream" (the actual image data). | 6 const EXIF_MARK_SOS = 0xffda; // Start of "stream" (the actual image data). |
| 7 const EXIF_MARK_SOF = 0xffc0; // Start of "frame" | 7 const EXIF_MARK_SOF = 0xffc0; // Start of "frame" |
| 8 const EXIF_MARK_EXIF = 0xffe1; // Start of exif block. | 8 const EXIF_MARK_EXIF = 0xffe1; // Start of exif block. |
| 9 | 9 |
| 10 const EXIF_ALIGN_LITTLE = 0x4949; // Indicates little endian exif data. | 10 const EXIF_ALIGN_LITTLE = 0x4949; // Indicates little endian exif data. |
| 11 const EXIF_ALIGN_BIG = 0x4d4d; // Indicates big endian exif data. | 11 const EXIF_ALIGN_BIG = 0x4d4d; // Indicates big endian exif data. |
| 12 | 12 |
| 13 const EXIF_TAG_TIFF = 0x002a; // First directory containing TIFF data. | 13 const EXIF_TAG_TIFF = 0x002a; // First directory containing TIFF data. |
| 14 const EXIF_TAG_GPSDATA = 0x8825; // Pointer from TIFF to the GPS directory. | 14 const EXIF_TAG_GPSDATA = 0x8825; // Pointer from TIFF to the GPS directory. |
| 15 const EXIF_TAG_EXIFDATA = 0x8769; // Pointer from TIFF to the EXIF IFD. | 15 const EXIF_TAG_EXIFDATA = 0x8769; // Pointer from TIFF to the EXIF IFD. |
| 16 const EXIF_TAG_SUBIFD = 0x014a; // Pointer from TIFF to "Extra" IFDs. | 16 const EXIF_TAG_SUBIFD = 0x014a; // Pointer from TIFF to "Extra" IFDs. |
| 17 | 17 |
| 18 const EXIF_TAG_JPG_THUMB_OFFSET = 0x0201; // Pointer from TIFF to thumbnail. | 18 const EXIF_TAG_JPG_THUMB_OFFSET = 0x0201; // Pointer from TIFF to thumbnail. |
| 19 const EXIF_TAG_JPG_THUMB_LENGTH = 0x0202; // Length of thumbnail data. | 19 const EXIF_TAG_JPG_THUMB_LENGTH = 0x0202; // Length of thumbnail data. |
| 20 | 20 |
| 21 const EXIF_TAG_ORIENTATION = 0x0112; | 21 const EXIF_TAG_ORIENTATION = 0x0112; |
| 22 const EXIF_TAG_X_DIMENSION = 0xA002; | 22 const EXIF_TAG_X_DIMENSION = 0xA002; |
| 23 const EXIF_TAG_Y_DIMENSION = 0xA003; | 23 const EXIF_TAG_Y_DIMENSION = 0xA003; |
| 24 | 24 |
| 25 function ExifParser(parent) { | 25 function ExifParser(parent) { |
| 26 MetadataParser.apply(this, [parent]); | 26 ImageParser.call(this, parent, 'jpeg', /\.jpe?g$/i); |
| 27 this.verbose = false; | |
| 28 this.mimeType = 'image/jpeg'; | |
| 29 } | 27 } |
| 30 | 28 |
| 31 ExifParser.parserType = 'exif'; | 29 ExifParser.prototype = {__proto__: ImageParser.prototype}; |
| 32 | |
| 33 ExifParser.prototype = {__proto__: MetadataParser.prototype}; | |
| 34 | |
| 35 ExifParser.prototype.urlFilter = /\.jpe?g$/i; | |
| 36 | 30 |
| 37 ExifParser.prototype.parse = function(file, callback, errorCallback) { | 31 ExifParser.prototype.parse = function(file, callback, errorCallback) { |
| 38 var self = this; | 32 var self = this; |
| 39 var currentStep = -1; | 33 var currentStep = -1; |
| 40 | 34 |
| 41 function nextStep(var_args) { | 35 function nextStep(var_args) { |
| 42 self.vlog('exif nextStep: ' + steps[currentStep + 1].name); | 36 self.vlog('exif nextStep: ' + steps[currentStep + 1].name); |
| 43 try { | 37 try { |
| 44 steps[++currentStep].apply(null, arguments); | 38 steps[++currentStep].apply(null, arguments); |
| 45 } catch(e) { | 39 } catch(e) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 75 mark = self.readMark(br); | 69 mark = self.readMark(br); |
| 76 if (mark == EXIF_MARK_SOF) { | 70 if (mark == EXIF_MARK_SOF) { |
| 77 // If we reached this section first then there is no EXIF data. | 71 // If we reached this section first then there is no EXIF data. |
| 78 // Extract image dimensions and return. | 72 // Extract image dimensions and return. |
| 79 | 73 |
| 80 // TODO(kaznacheev) Here we are assuming that SOF section lies within | 74 // TODO(kaznacheev) Here we are assuming that SOF section lies within |
| 81 // first 1024 bytes. This must be true for any normal JPEG file | 75 // first 1024 bytes. This must be true for any normal JPEG file |
| 82 // with no EXIF data. Still might want to handle this more carefully. | 76 // with no EXIF data. Still might want to handle this more carefully. |
| 83 if (br.tell() + 7 < buf.byteLength) { | 77 if (br.tell() + 7 < buf.byteLength) { |
| 84 br.seek(3, ByteReader.SEEK_CUR); | 78 br.seek(3, ByteReader.SEEK_CUR); |
| 85 var metadata = {mimeType: self.mimeType}; | 79 var metadata = self.createDefaultMetadata(); |
| 86 metadata.width = br.readScalar(2); | 80 metadata.width = br.readScalar(2); |
| 87 metadata.height = br.readScalar(2); | 81 metadata.height = br.readScalar(2); |
| 88 callback(metadata); | 82 callback(metadata); |
| 89 return; | 83 return; |
| 90 } | 84 } |
| 91 } | 85 } |
| 92 if (mark == EXIF_MARK_EXIF) { | 86 if (mark == EXIF_MARK_EXIF) { |
| 93 var length = self.readMarkLength(br); | 87 var length = self.readMarkLength(br); |
| 94 | 88 |
| 95 // Offsets inside the EXIF block are based after this bit of | 89 // Offsets inside the EXIF block are based after this bit of |
| (...skipping 22 matching lines...) Expand all Loading... |
| 118 if (order == EXIF_ALIGN_LITTLE) { | 112 if (order == EXIF_ALIGN_LITTLE) { |
| 119 br.setByteOrder(ByteReader.LITTLE_ENDIAN); | 113 br.setByteOrder(ByteReader.LITTLE_ENDIAN); |
| 120 } else if (order != EXIF_ALIGN_BIG) { | 114 } else if (order != EXIF_ALIGN_BIG) { |
| 121 return onError('Invalid alignment value: ' + order.toString(16)); | 115 return onError('Invalid alignment value: ' + order.toString(16)); |
| 122 } | 116 } |
| 123 | 117 |
| 124 var tag = br.readScalar(2); | 118 var tag = br.readScalar(2); |
| 125 if (tag != EXIF_TAG_TIFF) | 119 if (tag != EXIF_TAG_TIFF) |
| 126 return onError('Invalid TIFF tag: ' + tag.toString(16)); | 120 return onError('Invalid TIFF tag: ' + tag.toString(16)); |
| 127 | 121 |
| 128 var metadata = { | 122 var metadata = self.createDefaultMetadata(); |
| 129 metadataType: ExifParser.parserType, | 123 metadata.littleEndian = (order == EXIF_ALIGN_LITTLE); |
| 130 mimeType: self.mimeType, | 124 metadata.ifd = { |
| 131 littleEndian: (order == EXIF_ALIGN_LITTLE), | 125 image: {}, |
| 132 ifd: { | 126 thumbnail: {} |
| 133 image: {}, | |
| 134 thumbnail: {} | |
| 135 } | |
| 136 }; | 127 }; |
| 137 var directoryOffset = br.readScalar(4); | 128 var directoryOffset = br.readScalar(4); |
| 138 | 129 |
| 139 // Image directory. | 130 // Image directory. |
| 140 self.vlog('Read image directory.'); | 131 self.vlog('Read image directory.'); |
| 141 br.seek(directoryOffset); | 132 br.seek(directoryOffset); |
| 142 directoryOffset = self.readDirectory(br, metadata.ifd.image); | 133 directoryOffset = self.readDirectory(br, metadata.ifd.image); |
| 143 metadata.imageTransform = self.parseOrientation(metadata.ifd.image); | 134 metadata.imageTransform = self.parseOrientation(metadata.ifd.image); |
| 144 | 135 |
| 145 // Thumbnail Directory chained from the end of the image directory. | 136 // Thumbnail Directory chained from the end of the image directory. |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 return { | 345 return { |
| 355 scaleX: ExifParser.SCALEX[index], | 346 scaleX: ExifParser.SCALEX[index], |
| 356 scaleY: ExifParser.SCALEY[index], | 347 scaleY: ExifParser.SCALEY[index], |
| 357 rotate90: ExifParser.ROTATE90[index] | 348 rotate90: ExifParser.ROTATE90[index] |
| 358 } | 349 } |
| 359 } | 350 } |
| 360 return null; | 351 return null; |
| 361 }; | 352 }; |
| 362 | 353 |
| 363 MetadataDispatcher.registerParserClass(ExifParser); | 354 MetadataDispatcher.registerParserClass(ExifParser); |
| OLD | NEW |