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 |