Index: trunk/phase3/resources/mediawiki.util/mediawiki.util.jpegmeta.js |
— | — | @@ -1,733 +0,0 @@ |
2 | | -/* This is JsJpegMeta 1.0, ported to MediaWiki ResourceLoader by Bryan Tong Minh */ |
3 | | -/* The following lines where changed with respect to the original: 54, 625-627 */ |
4 | | - |
5 | | -( function( $, mw ) { |
6 | | - |
7 | | - /* JsJpegMeta starts here */ |
8 | | - |
9 | | - /* |
10 | | - Copyright (c) 2009 Ben Leslie |
11 | | - |
12 | | - Permission is hereby granted, free of charge, to any person obtaining a copy |
13 | | - of this software and associated documentation files (the "Software"), to deal |
14 | | - in the Software without restriction, including without limitation the rights |
15 | | - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
16 | | - copies of the Software, and to permit persons to whom the Software is |
17 | | - furnished to do so, subject to the following conditions: |
18 | | - |
19 | | - The above copyright notice and this permission notice shall be included in |
20 | | - all copies or substantial portions of the Software. |
21 | | - |
22 | | - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
23 | | - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
24 | | - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
25 | | - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
26 | | - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
27 | | - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
28 | | - THE SOFTWARE. |
29 | | - */ |
30 | | - |
31 | | - /* |
32 | | - This JavaScript library is used to parse meta-data from files |
33 | | - with mime-type image/jpeg. |
34 | | - |
35 | | - Include it with something like: |
36 | | - |
37 | | - <script type="text/javascript" src="jpegmeta.js"></script> |
38 | | - |
39 | | - This adds a single 'module' object called 'JpegMeta' to the global |
40 | | - namespace. |
41 | | - |
42 | | - Public Functions |
43 | | - ---------------- |
44 | | - JpegMeta.parseNum - parse unsigned integers from binary data |
45 | | - JpegMeta.parseSnum - parse signed integers from binary data |
46 | | - |
47 | | - Public Classes |
48 | | - -------------- |
49 | | - JpegMeta.Rational - A rational number class |
50 | | - JpegMeta.JfifSegment |
51 | | - JpegMeta.ExifSegment |
52 | | - JpegMeta.JpegFile - Primary class for Javascript parsing |
53 | | - */ |
54 | | - |
55 | | - var JpegMeta = {}; |
56 | | - this.JpegMeta = JpegMeta; // I have no clue why I need this magic... -- Bryan |
57 | | - |
58 | | - /* |
59 | | - parse an unsigned number of size bytes at offset in some binary string data. |
60 | | - If endian |
61 | | - is "<" parse the data as little endian, if endian |
62 | | - is ">" parse as big-endian. |
63 | | - */ |
64 | | - JpegMeta.parseNum = function parseNum(endian, data, offset, size) { |
65 | | - var i; |
66 | | - var ret; |
67 | | - var big_endian = (endian === ">"); |
68 | | - if (offset === undefined) offset = 0; |
69 | | - if (size === undefined) size = data.length - offset; |
70 | | - for (big_endian ? i = offset : i = offset + size - 1; |
71 | | - big_endian ? i < offset + size : i >= offset; |
72 | | - big_endian ? i++ : i--) { |
73 | | - ret <<= 8; |
74 | | - ret += data.charCodeAt(i); |
75 | | - } |
76 | | - return ret; |
77 | | - }; |
78 | | - |
79 | | - /* |
80 | | - parse an signed number of size bytes at offset in some binary string data. |
81 | | - If endian |
82 | | - is "<" parse the data as little endian, if endian |
83 | | - is ">" parse as big-endian. |
84 | | - */ |
85 | | - JpegMeta.parseSnum = function parseSnum(endian, data, offset, size) { |
86 | | - var i; |
87 | | - var ret; |
88 | | - var neg; |
89 | | - var big_endian = (endian === ">"); |
90 | | - if (offset === undefined) offset = 0; |
91 | | - if (size === undefined) size = data.length - offset; |
92 | | - for (big_endian ? i = offset : i = offset + size - 1; |
93 | | - big_endian ? i < offset + size : i >= offset; |
94 | | - big_endian ? i++ : i--) { |
95 | | - if (neg === undefined) { |
96 | | - /* Negative if top bit is set */ |
97 | | - neg = (data.charCodeAt(i) & 0x80) === 0x80; |
98 | | - } |
99 | | - ret <<= 8; |
100 | | - /* If it is negative we invert the bits */ |
101 | | - ret += neg ? ~data.charCodeAt(i) & 0xff: data.charCodeAt(i); |
102 | | - } |
103 | | - if (neg) { |
104 | | - /* If it is negative we do two's complement */ |
105 | | - ret += 1; |
106 | | - ret *= -1; |
107 | | - } |
108 | | - return ret; |
109 | | - }; |
110 | | - |
111 | | - /* Rational number class */ |
112 | | - JpegMeta.Rational = function Rational(num, den) |
113 | | - { |
114 | | - this.num = num; |
115 | | - this.den = den || 1; |
116 | | - return this; |
117 | | - }; |
118 | | - |
119 | | - /* Rational number methods */ |
120 | | - JpegMeta.Rational.prototype.toString = function toString() { |
121 | | - if (this.num === 0) { |
122 | | - return "" + this.num |
123 | | - } |
124 | | - if (this.den === 1) { |
125 | | - return "" + this.num; |
126 | | - } |
127 | | - if (this.num === 1) { |
128 | | - return this.num + " / " + this.den; |
129 | | - } |
130 | | - return this.num / this.den; // + "/" + this.den; |
131 | | - }; |
132 | | - |
133 | | - JpegMeta.Rational.prototype.asFloat = function asFloat() { |
134 | | - return this.num / this.den; |
135 | | - }; |
136 | | - |
137 | | - /* MetaGroup class */ |
138 | | - JpegMeta.MetaGroup = function MetaGroup(fieldName, description) { |
139 | | - this.fieldName = fieldName; |
140 | | - this.description = description; |
141 | | - this.metaProps = {}; |
142 | | - return this; |
143 | | - }; |
144 | | - |
145 | | - JpegMeta.MetaGroup.prototype._addProperty = function _addProperty(fieldName, description, value) { |
146 | | - var property = new JpegMeta.MetaProp(fieldName, description, value); |
147 | | - this[property.fieldName] = property; |
148 | | - this.metaProps[property.fieldName] = property; |
149 | | - }; |
150 | | - |
151 | | - JpegMeta.MetaGroup.prototype.toString = function toString() { |
152 | | - return "[MetaGroup " + this.description + "]"; |
153 | | - }; |
154 | | - |
155 | | - /* MetaProp class */ |
156 | | - JpegMeta.MetaProp = function MetaProp(fieldName, description, value) { |
157 | | - this.fieldName = fieldName; |
158 | | - this.description = description; |
159 | | - this.value = value; |
160 | | - return this; |
161 | | - }; |
162 | | - |
163 | | - JpegMeta.MetaProp.prototype.toString = function toString() { |
164 | | - return "" + this.value; |
165 | | - }; |
166 | | - |
167 | | - /* JpegFile class */ |
168 | | - JpegMeta.JpegFile = function JpegFile(binary_data, filename) { |
169 | | - /* Change this to EOI if we want to parse. */ |
170 | | - var break_segment = this._SOS; |
171 | | - |
172 | | - this.metaGroups = {}; |
173 | | - this._binary_data = binary_data; |
174 | | - this.filename = filename; |
175 | | - |
176 | | - /* Go through and parse. */ |
177 | | - var pos = 0; |
178 | | - var pos_start_of_segment = 0; |
179 | | - var delim; |
180 | | - var mark; |
181 | | - var _mark; |
182 | | - var segsize; |
183 | | - var headersize; |
184 | | - var mark_code; |
185 | | - var mark_fn; |
186 | | - |
187 | | - /* Check to see if this looks like a JPEG file */ |
188 | | - if (this._binary_data.slice(0, 2) !== this._SOI_MARKER) { |
189 | | - throw new Error("Doesn't look like a JPEG file. First two bytes are " + |
190 | | - this._binary_data.charCodeAt(0) + "," + |
191 | | - this._binary_data.charCodeAt(1) + "."); |
192 | | - } |
193 | | - |
194 | | - pos += 2; |
195 | | - |
196 | | - while (pos < this._binary_data.length) { |
197 | | - delim = this._binary_data.charCodeAt(pos++); |
198 | | - mark = this._binary_data.charCodeAt(pos++); |
199 | | - |
200 | | - pos_start_of_segment = pos; |
201 | | - |
202 | | - if (delim != this._DELIM) { |
203 | | - break; |
204 | | - } |
205 | | - |
206 | | - if (mark === break_segment) { |
207 | | - break; |
208 | | - } |
209 | | - |
210 | | - headersize = JpegMeta.parseNum(">", this._binary_data, pos, 2); |
211 | | - |
212 | | - /* Find the end */ |
213 | | - pos += headersize; |
214 | | - while (pos < this._binary_data.length) { |
215 | | - delim = this._binary_data.charCodeAt(pos++); |
216 | | - if (delim == this._DELIM) { |
217 | | - _mark = this._binary_data.charCodeAt(pos++); |
218 | | - if (_mark != 0x0) { |
219 | | - pos -= 2; |
220 | | - break; |
221 | | - } |
222 | | - } |
223 | | - } |
224 | | - |
225 | | - segsize = pos - pos_start_of_segment; |
226 | | - |
227 | | - if (this._markers[mark]) { |
228 | | - mark_code = this._markers[mark][0]; |
229 | | - mark_fn = this._markers[mark][1]; |
230 | | - } else { |
231 | | - mark_code = "UNKN"; |
232 | | - mark_fn = undefined; |
233 | | - } |
234 | | - |
235 | | - if (mark_fn) { |
236 | | - this[mark_fn](mark, pos_start_of_segment + 2); |
237 | | - } |
238 | | - |
239 | | - } |
240 | | - |
241 | | - if (this.general === undefined) { |
242 | | - throw Error("Invalid JPEG file."); |
243 | | - } |
244 | | - |
245 | | - return this; |
246 | | - }; |
247 | | - |
248 | | - this.JpegMeta.JpegFile.prototype.toString = function () { |
249 | | - return "[JpegFile " + this.filename + " " + |
250 | | - this.general.type + " " + |
251 | | - this.general.pixelWidth + "x" + |
252 | | - this.general.pixelHeight + |
253 | | - " Depth: " + this.general.depth + "]"; |
254 | | - }; |
255 | | - |
256 | | - /* Some useful constants */ |
257 | | - this.JpegMeta.JpegFile.prototype._SOI_MARKER = '\xff\xd8'; |
258 | | - this.JpegMeta.JpegFile.prototype._DELIM = 0xff; |
259 | | - this.JpegMeta.JpegFile.prototype._EOI = 0xd9; |
260 | | - this.JpegMeta.JpegFile.prototype._SOS = 0xda; |
261 | | - |
262 | | - this.JpegMeta.JpegFile.prototype._sofHandler = function _sofHandler (mark, pos) { |
263 | | - if (this.general !== undefined) { |
264 | | - throw Error("Unexpected multiple-frame image"); |
265 | | - } |
266 | | - |
267 | | - this._addMetaGroup("general", "General"); |
268 | | - this.general._addProperty("depth", "Depth", JpegMeta.parseNum(">", this._binary_data, pos, 1)); |
269 | | - this.general._addProperty("pixelHeight", "Pixel Height", JpegMeta.parseNum(">", this._binary_data, pos + 1, 2)); |
270 | | - this.general._addProperty("pixelWidth", "Pixel Width",JpegMeta.parseNum(">", this._binary_data, pos + 3, 2)); |
271 | | - this.general._addProperty("type", "Type", this._markers[mark][2]); |
272 | | - }; |
273 | | - |
274 | | - /* JFIF idents */ |
275 | | - this.JpegMeta.JpegFile.prototype._JFIF_IDENT = "JFIF\x00"; |
276 | | - this.JpegMeta.JpegFile.prototype._JFXX_IDENT = "JFXX\x00"; |
277 | | - |
278 | | - /* EXIF idents */ |
279 | | - this.JpegMeta.JpegFile.prototype._EXIF_IDENT = "Exif\x00"; |
280 | | - |
281 | | - /* TIFF types */ |
282 | | - this.JpegMeta.JpegFile.prototype._types = { |
283 | | - /* The format is identifier : ["type name", type_size_in_bytes ] */ |
284 | | - 1 : ["BYTE", 1], |
285 | | - 2 : ["ASCII", 1], |
286 | | - 3 : ["SHORT", 2], |
287 | | - 4 : ["LONG", 4], |
288 | | - 5 : ["RATIONAL", 8], |
289 | | - 6 : ["SBYTE", 1], |
290 | | - 7 : ["UNDEFINED", 1], |
291 | | - 8 : ["SSHORT", 2], |
292 | | - 9 : ["SLONG", 4], |
293 | | - 10 : ["SRATIONAL", 8], |
294 | | - 11 : ["FLOAT", 4], |
295 | | - 12 : ["DOUBLE", 8], |
296 | | - }; |
297 | | - |
298 | | - this.JpegMeta.JpegFile.prototype._tifftags = { |
299 | | - /* A. Tags relating to image data structure */ |
300 | | - 256 : ["Image width", "ImageWidth"], |
301 | | - 257 : ["Image height", "ImageLength"], |
302 | | - 258 : ["Number of bits per component", "BitsPerSample"], |
303 | | - 259 : ["Compression scheme", "Compression", |
304 | | - {1 : "uncompressed", 6 : "JPEG compression" }], |
305 | | - 262 : ["Pixel composition", "PhotmetricInerpretation", |
306 | | - {2 : "RGB", 6 : "YCbCr"}], |
307 | | - 274 : ["Orientation of image", "Orientation", |
308 | | - /* FIXME: Check the mirror-image / reverse encoding and rotation */ |
309 | | - {1 : "Normal", 2 : "Reverse?", |
310 | | - 3 : "Upside-down", 4 : "Upside-down Reverse", |
311 | | - 5 : "90 degree CW", 6 : "90 degree CW reverse", |
312 | | - 7 : "90 degree CCW", 8 : "90 degree CCW reverse",}], |
313 | | - 277 : ["Number of components", "SamplesPerPixel"], |
314 | | - 284 : ["Image data arrangement", "PlanarConfiguration", |
315 | | - {1 : "chunky format", 2 : "planar format"}], |
316 | | - 530 : ["Subsampling ratio of Y to C", "YCbCrSubSampling"], |
317 | | - 531 : ["Y and C positioning", "YCbCrPositioning", |
318 | | - {1 : "centered", 2 : "co-sited"}], |
319 | | - 282 : ["X Resolution", "XResolution"], |
320 | | - 283 : ["Y Resolution", "YResolution"], |
321 | | - 296 : ["Resolution Unit", "ResolutionUnit", |
322 | | - {2 : "inches", 3 : "centimeters"}], |
323 | | - /* B. Tags realting to recording offset */ |
324 | | - 273 : ["Image data location", "StripOffsets"], |
325 | | - 278 : ["Number of rows per strip", "RowsPerStrip"], |
326 | | - 279 : ["Bytes per compressed strip", "StripByteCounts"], |
327 | | - 513 : ["Offset to JPEG SOI", "JPEGInterchangeFormat"], |
328 | | - 514 : ["Bytes of JPEG Data", "JPEGInterchangeFormatLength"], |
329 | | - /* C. Tags relating to image data characteristics */ |
330 | | - 301 : ["Transfer function", "TransferFunction"], |
331 | | - 318 : ["White point chromaticity", "WhitePoint"], |
332 | | - 319 : ["Chromaticities of primaries", "PrimaryChromaticities"], |
333 | | - 529 : ["Color space transformation matrix coefficients", "YCbCrCoefficients"], |
334 | | - 532 : ["Pair of black and white reference values", "ReferenceBlackWhite"], |
335 | | - /* D. Other tags */ |
336 | | - 306 : ["Date and time", "DateTime"], |
337 | | - 270 : ["Image title", "ImageDescription"], |
338 | | - 271 : ["Make", "Make"], |
339 | | - 272 : ["Model", "Model"], |
340 | | - 305 : ["Software", "Software"], |
341 | | - 315 : ["Person who created the image", "Artist"], |
342 | | - 316 : ["Host Computer", "HostComputer"], |
343 | | - 33432 : ["Copyright holder", "Copyright"], |
344 | | - |
345 | | - 34665 : ["Exif tag", "ExifIfdPointer"], |
346 | | - 34853 : ["GPS tag", "GPSInfoIfdPointer"], |
347 | | - }; |
348 | | - |
349 | | - this.JpegMeta.JpegFile.prototype._exiftags = { |
350 | | - /* Tag Support Levels (2) - 0th IFX Exif Private Tags */ |
351 | | - /* A. Tags Relating to Version */ |
352 | | - 36864 : ["Exif Version", "ExifVersion"], |
353 | | - 40960 : ["FlashPix Version", "FlashpixVersion"], |
354 | | - |
355 | | - /* B. Tag Relating to Image Data Characteristics */ |
356 | | - 40961 : ["Color Space", "ColorSpace"], |
357 | | - |
358 | | - /* C. Tags Relating to Image Configuration */ |
359 | | - 37121 : ["Meaning of each component", "ComponentsConfiguration"], |
360 | | - 37122 : ["Compressed Bits Per Pixel", "CompressedBitsPerPixel"], |
361 | | - 40962 : ["Pixel X Dimension", "PixelXDimension"], |
362 | | - 40963 : ["Pixel Y Dimension", "PixelYDimension"], |
363 | | - |
364 | | - /* D. Tags Relating to User Information */ |
365 | | - 37500 : ["Manufacturer notes", "MakerNote"], |
366 | | - 37510 : ["User comments", "UserComment"], |
367 | | - |
368 | | - /* E. Tag Relating to Related File Information */ |
369 | | - 40964 : ["Related audio file", "RelatedSoundFile"], |
370 | | - |
371 | | - /* F. Tags Relating to Date and Time */ |
372 | | - 36867 : ["Date Time Original", "DateTimeOriginal"], |
373 | | - 36868 : ["Date Time Digitized", "DateTimeDigitized"], |
374 | | - 37520 : ["DateTime subseconds", "SubSecTime"], |
375 | | - 37521 : ["DateTimeOriginal subseconds", "SubSecTimeOriginal"], |
376 | | - 37522 : ["DateTimeDigitized subseconds", "SubSecTimeDigitized"], |
377 | | - |
378 | | - /* G. Tags Relating to Picture-Taking Conditions */ |
379 | | - 33434 : ["Exposure time", "ExposureTime"], |
380 | | - 33437 : ["FNumber", "FNumber"], |
381 | | - 34850 : ["Exposure program", "ExposureProgram"], |
382 | | - 34852 : ["Spectral sensitivity", "SpectralSensitivity"], |
383 | | - 34855 : ["ISO Speed Ratings", "ISOSpeedRatings"], |
384 | | - 34856 : ["Optoelectric coefficient", "OECF"], |
385 | | - 37377 : ["Shutter Speed", "ShutterSpeedValue"], |
386 | | - 37378 : ["Aperture Value", "ApertureValue"], |
387 | | - 37379 : ["Brightness", "BrightnessValue"], |
388 | | - 37380 : ["Exposure Bias Value", "ExposureBiasValue"], |
389 | | - 37381 : ["Max Aperture Value", "MaxApertureValue"], |
390 | | - 37382 : ["Subject Distance", "SubjectDistance"], |
391 | | - 37383 : ["Metering Mode", "MeteringMode"], |
392 | | - 37384 : ["Light Source", "LightSource"], |
393 | | - 37385 : ["Flash", "Flash"], |
394 | | - 37386 : ["Focal Length", "FocalLength"], |
395 | | - 37396 : ["Subject Area", "SubjectArea"], |
396 | | - 41483 : ["Flash Energy", "FlashEnergy"], |
397 | | - 41484 : ["Spatial Frequency Response", "SpatialFrequencyResponse"], |
398 | | - 41486 : ["Focal Plane X Resolution", "FocalPlaneXResolution"], |
399 | | - 41487 : ["Focal Plane Y Resolution", "FocalPlaneYResolution"], |
400 | | - 41488 : ["Focal Plane Resolution Unit", "FocalPlaneResolutionUnit"], |
401 | | - 41492 : ["Subject Location", "SubjectLocation"], |
402 | | - 41493 : ["Exposure Index", "ExposureIndex"], |
403 | | - 41495 : ["Sensing Method", "SensingMethod"], |
404 | | - 41728 : ["File Source", "FileSource"], |
405 | | - 41729 : ["Scene Type", "SceneType"], |
406 | | - 41730 : ["CFA Pattern", "CFAPattern"], |
407 | | - 41985 : ["Custom Rendered", "CustomRendered"], |
408 | | - 41986 : ["Exposure Mode", "Exposure Mode"], |
409 | | - 41987 : ["White Balance", "WhiteBalance"], |
410 | | - 41988 : ["Digital Zoom Ratio", "DigitalZoomRatio"], |
411 | | - 41990 : ["Scene Capture Type", "SceneCaptureType"], |
412 | | - 41991 : ["Gain Control", "GainControl"], |
413 | | - 41992 : ["Contrast", "Contrast"], |
414 | | - 41993 : ["Saturation", "Saturation"], |
415 | | - 41994 : ["Sharpness", "Sharpness"], |
416 | | - 41995 : ["Device settings description", "DeviceSettingDescription"], |
417 | | - 41996 : ["Subject distance range", "SubjectDistanceRange"], |
418 | | - |
419 | | - /* H. Other Tags */ |
420 | | - 42016 : ["Unique image ID", "ImageUniqueID"], |
421 | | - |
422 | | - 40965 : ["Interoperability tag", "InteroperabilityIFDPointer"], |
423 | | - }; |
424 | | - |
425 | | - this.JpegMeta.JpegFile.prototype._gpstags = { |
426 | | - /* A. Tags Relating to GPS */ |
427 | | - 0 : ["GPS tag version", "GPSVersionID"], |
428 | | - 1 : ["North or South Latitude", "GPSLatitudeRef"], |
429 | | - 2 : ["Latitude", "GPSLatitude"], |
430 | | - 3 : ["East or West Longitude", "GPSLongitudeRef"], |
431 | | - 4 : ["Longitude", "GPSLongitude"], |
432 | | - 5 : ["Altitude reference", "GPSAltitudeRef"], |
433 | | - 6 : ["Altitude", "GPSAltitude"], |
434 | | - 7 : ["GPS time (atomic clock)", "GPSTimeStamp"], |
435 | | - 8 : ["GPS satellites usedd for measurement", "GPSSatellites"], |
436 | | - 9 : ["GPS receiver status", "GPSStatus"], |
437 | | - 10 : ["GPS mesaurement mode", "GPSMeasureMode"], |
438 | | - 11 : ["Measurement precision", "GPSDOP"], |
439 | | - 12 : ["Speed unit", "GPSSpeedRef"], |
440 | | - 13 : ["Speed of GPS receiver", "GPSSpeed"], |
441 | | - 14 : ["Reference for direction of movement", "GPSTrackRef"], |
442 | | - 15 : ["Direction of movement", "GPSTrack"], |
443 | | - 16 : ["Reference for direction of image", "GPSImgDirectionRef"], |
444 | | - 17 : ["Direction of image", "GPSImgDirection"], |
445 | | - 18 : ["Geodetic survey data used", "GPSMapDatum"], |
446 | | - 19 : ["Reference for latitude of destination", "GPSDestLatitudeRef"], |
447 | | - 20 : ["Latitude of destination", "GPSDestLatitude"], |
448 | | - 21 : ["Reference for longitude of destination", "GPSDestLongitudeRef"], |
449 | | - 22 : ["Longitude of destination", "GPSDestLongitude"], |
450 | | - 23 : ["Reference for bearing of destination", "GPSDestBearingRef"], |
451 | | - 24 : ["Bearing of destination", "GPSDestBearing"], |
452 | | - 25 : ["Reference for distance to destination", "GPSDestDistanceRef"], |
453 | | - 26 : ["Distance to destination", "GPSDestDistance"], |
454 | | - 27 : ["Name of GPS processing method", "GPSProcessingMethod"], |
455 | | - 28 : ["Name of GPS area", "GPSAreaInformation"], |
456 | | - 29 : ["GPS Date", "GPSDateStamp"], |
457 | | - 30 : ["GPS differential correction", "GPSDifferential"], |
458 | | - }; |
459 | | - |
460 | | - this.JpegMeta.JpegFile.prototype._markers = { |
461 | | - /* Start Of Frame markers, non-differential, Huffman coding */ |
462 | | - 0xc0: ["SOF0", "_sofHandler", "Baseline DCT"], |
463 | | - 0xc1: ["SOF1", "_sofHandler", "Extended sequential DCT"], |
464 | | - 0xc2: ["SOF2", "_sofHandler", "Progressive DCT"], |
465 | | - 0xc3: ["SOF3", "_sofHandler", "Lossless (sequential)"], |
466 | | - |
467 | | - /* Start Of Frame markers, differential, Huffman coding */ |
468 | | - 0xc5: ["SOF5", "_sofHandler", "Differential sequential DCT"], |
469 | | - 0xc6: ["SOF6", "_sofHandler", "Differential progressive DCT"], |
470 | | - 0xc7: ["SOF7", "_sofHandler", "Differential lossless (sequential)"], |
471 | | - |
472 | | - /* Start Of Frame markers, non-differential, arithmetic coding */ |
473 | | - 0xc8: ["JPG", null, "Reserved for JPEG extensions"], |
474 | | - 0xc9: ["SOF9", "_sofHandler", "Extended sequential DCT"], |
475 | | - 0xca: ["SOF10", "_sofHandler", "Progressive DCT"], |
476 | | - 0xcb: ["SOF11", "_sofHandler", "Lossless (sequential)"], |
477 | | - |
478 | | - /* Start Of Frame markers, differential, arithmetic coding */ |
479 | | - 0xcd: ["SOF13", "_sofHandler", "Differential sequential DCT"], |
480 | | - 0xce: ["SOF14", "_sofHandler", "Differential progressive DCT"], |
481 | | - 0xcf: ["SOF15", "_sofHandler", "Differential lossless (sequential)"], |
482 | | - |
483 | | - /* Huffman table specification */ |
484 | | - 0xc4: ["DHT", null, "Define Huffman table(s)"], |
485 | | - 0xcc: ["DAC", null, "Define arithmetic coding conditioning(s)"], |
486 | | - |
487 | | - /* Restart interval termination" */ |
488 | | - 0xd0: ["RST0", null, "Restart with modulo 8 count “0”"], |
489 | | - 0xd1: ["RST1", null, "Restart with modulo 8 count “1”"], |
490 | | - 0xd2: ["RST2", null, "Restart with modulo 8 count “2”"], |
491 | | - 0xd3: ["RST3", null, "Restart with modulo 8 count “3”"], |
492 | | - 0xd4: ["RST4", null, "Restart with modulo 8 count “4”"], |
493 | | - 0xd5: ["RST5", null, "Restart with modulo 8 count “5”"], |
494 | | - 0xd6: ["RST6", null, "Restart with modulo 8 count “6”"], |
495 | | - 0xd7: ["RST7", null, "Restart with modulo 8 count “7”"], |
496 | | - |
497 | | - /* Other markers */ |
498 | | - 0xd8: ["SOI", null, "Start of image"], |
499 | | - 0xd9: ["EOI", null, "End of image"], |
500 | | - 0xda: ["SOS", null, "Start of scan"], |
501 | | - 0xdb: ["DQT", null, "Define quantization table(s)"], |
502 | | - 0xdc: ["DNL", null, "Define number of lines"], |
503 | | - 0xdd: ["DRI", null, "Define restart interval"], |
504 | | - 0xde: ["DHP", null, "Define hierarchical progression"], |
505 | | - 0xdf: ["EXP", null, "Expand reference component(s)"], |
506 | | - 0xe0: ["APP0", "_app0Handler", "Reserved for application segments"], |
507 | | - 0xe1: ["APP1", "_app1Handler"], |
508 | | - 0xe2: ["APP2", null], |
509 | | - 0xe3: ["APP3", null], |
510 | | - 0xe4: ["APP4", null], |
511 | | - 0xe5: ["APP5", null], |
512 | | - 0xe6: ["APP6", null], |
513 | | - 0xe7: ["APP7", null], |
514 | | - 0xe8: ["APP8", null], |
515 | | - 0xe9: ["APP9", null], |
516 | | - 0xea: ["APP10", null], |
517 | | - 0xeb: ["APP11", null], |
518 | | - 0xec: ["APP12", null], |
519 | | - 0xed: ["APP13", null], |
520 | | - 0xee: ["APP14", null], |
521 | | - 0xef: ["APP15", null], |
522 | | - 0xf0: ["JPG0", null], /* Reserved for JPEG extensions */ |
523 | | - 0xf1: ["JPG1", null], |
524 | | - 0xf2: ["JPG2", null], |
525 | | - 0xf3: ["JPG3", null], |
526 | | - 0xf4: ["JPG4", null], |
527 | | - 0xf5: ["JPG5", null], |
528 | | - 0xf6: ["JPG6", null], |
529 | | - 0xf7: ["JPG7", null], |
530 | | - 0xf8: ["JPG8", null], |
531 | | - 0xf9: ["JPG9", null], |
532 | | - 0xfa: ["JPG10", null], |
533 | | - 0xfb: ["JPG11", null], |
534 | | - 0xfc: ["JPG12", null], |
535 | | - 0xfd: ["JPG13", null], |
536 | | - 0xfe: ["COM", null], /* Comment */ |
537 | | - |
538 | | - /* Reserved markers */ |
539 | | - 0x01: ["JPG13", null], /* For temporary private use in arithmetic coding */ |
540 | | - /* 02 -> bf are reserverd */ |
541 | | - }; |
542 | | - |
543 | | - /* Private methods */ |
544 | | - this.JpegMeta.JpegFile.prototype._addMetaGroup = function _addMetaGroup(name, description) { |
545 | | - var group = new JpegMeta.MetaGroup(name, description); |
546 | | - this[group.fieldName] = group; |
547 | | - this.metaGroups[group.fieldName] = group; |
548 | | - return group; |
549 | | - }; |
550 | | - |
551 | | - this.JpegMeta.JpegFile.prototype._parseIfd = function _parseIfd(endian, _binary_data, base, ifd_offset, tags, name, description) { |
552 | | - var num_fields = JpegMeta.parseNum(endian, _binary_data, base + ifd_offset, 2); |
553 | | - /* Per tag variables */ |
554 | | - var i, j; |
555 | | - var tag_base; |
556 | | - var tag_field; |
557 | | - var type, type_field, type_size; |
558 | | - var num_values; |
559 | | - var value_offset; |
560 | | - var value; |
561 | | - var _val; |
562 | | - var num; |
563 | | - var den; |
564 | | - |
565 | | - var group; |
566 | | - |
567 | | - group = this._addMetaGroup(name, description); |
568 | | - |
569 | | - for (var i = 0; i < num_fields; i++) { |
570 | | - /* parse the field */ |
571 | | - tag_base = base + ifd_offset + 2 + (i * 12); |
572 | | - tag_field = JpegMeta.parseNum(endian, _binary_data, tag_base, 2); |
573 | | - type_field = JpegMeta.parseNum(endian, _binary_data, tag_base + 2, 2); |
574 | | - num_values = JpegMeta.parseNum(endian, _binary_data, tag_base + 4, 4); |
575 | | - value_offset = JpegMeta.parseNum(endian, _binary_data, tag_base + 8, 4); |
576 | | - if (this._types[type_field] === undefined) { |
577 | | - continue; |
578 | | - } |
579 | | - type = this._types[type_field][0]; |
580 | | - type_size = this._types[type_field][1]; |
581 | | - |
582 | | - if (type_size * num_values <= 4) { |
583 | | - /* Data is in-line */ |
584 | | - value_offset = tag_base + 8; |
585 | | - } else { |
586 | | - value_offset = base + value_offset; |
587 | | - } |
588 | | - |
589 | | - /* Read the value */ |
590 | | - if (type == "UNDEFINED") { |
591 | | - value = _binary_data.slice(value_offset, value_offset + num_values); |
592 | | - } else if (type == "ASCII") { |
593 | | - value = _binary_data.slice(value_offset, value_offset + num_values); |
594 | | - value = value.split('\x00')[0]; |
595 | | - /* strip trail nul */ |
596 | | - } else { |
597 | | - value = new Array(); |
598 | | - for (j = 0; j < num_values; j++, value_offset += type_size) { |
599 | | - if (type == "BYTE" || type == "SHORT" || type == "LONG") { |
600 | | - value.push(JpegMeta.parseNum(endian, _binary_data, value_offset, type_size)); |
601 | | - } |
602 | | - if (type == "SBYTE" || type == "SSHORT" || type == "SLONG") { |
603 | | - value.push(JpegMeta.parseSnum(endian, _binary_data, value_offset, type_size)); |
604 | | - } |
605 | | - if (type == "RATIONAL") { |
606 | | - num = JpegMeta.parseNum(endian, _binary_data, value_offset, 4); |
607 | | - den = JpegMeta.parseNum(endian, _binary_data, value_offset + 4, 4); |
608 | | - value.push(new JpegMeta.Rational(num, den)); |
609 | | - } |
610 | | - if (type == "SRATIONAL") { |
611 | | - num = JpegMeta.parseSnum(endian, _binary_data, value_offset, 4); |
612 | | - den = JpegMeta.parseSnum(endian, _binary_data, value_offset + 4, 4); |
613 | | - value.push(new JpegMeta.Rational(num, den)); |
614 | | - } |
615 | | - value.push(); |
616 | | - } |
617 | | - if (num_values === 1) { |
618 | | - value = value[0]; |
619 | | - } |
620 | | - } |
621 | | - if (tags[tag_field] !== undefined) { |
622 | | - group._addProperty(tags[tag_field][1], tags[tag_field][0], value); |
623 | | - } |
624 | | - } |
625 | | - }; |
626 | | - |
627 | | - this.JpegMeta.JpegFile.prototype._jfifHandler = function _jfifHandler(mark, pos) { |
628 | | - if (this.jfif !== undefined) { |
629 | | - throw Error("Multiple JFIF segments found"); |
630 | | - } |
631 | | - this._addMetaGroup("jfif", "JFIF"); |
632 | | - this.jfif._addProperty("version_major", "Version Major", this._binary_data.charCodeAt(pos + 5)); |
633 | | - this.jfif._addProperty("version_minor", "Version Minor", this._binary_data.charCodeAt(pos + 6)); |
634 | | - this.jfif._addProperty("version", "JFIF Version", this.jfif.version_major.value + "." + this.jfif.version_minor.value); |
635 | | - this.jfif._addProperty("units", "Density Unit", this._binary_data.charCodeAt(pos + 7)); |
636 | | - this.jfif._addProperty("Xdensity", "X density", JpegMeta.parseNum(">", this._binary_data, pos + 8, 2)); |
637 | | - this.jfif._addProperty("Ydensity", "Y Density", JpegMeta.parseNum(">", this._binary_data, pos + 10, 2)); |
638 | | - this.jfif._addProperty("Xthumbnail", "X Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 12, 1)); |
639 | | - this.jfif._addProperty("Ythumbnail", "Y Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 13, 1)); |
640 | | - }; |
641 | | - |
642 | | - /* Handle app0 segments */ |
643 | | - this.JpegMeta.JpegFile.prototype._app0Handler = function app0Handler(mark, pos) { |
644 | | - var ident = this._binary_data.slice(pos, pos + 5); |
645 | | - if (ident == this._JFIF_IDENT) { |
646 | | - this._jfifHandler(mark, pos); |
647 | | - } else if (ident == this._JFXX_IDENT) { |
648 | | - /* Don't handle JFXX Ident yet */ |
649 | | - } else { |
650 | | - /* Don't know about other idents */ |
651 | | - } |
652 | | - }; |
653 | | - |
654 | | - /* Handle app1 segments */ |
655 | | - this.JpegMeta.JpegFile.prototype._app1Handler = function _app1Handler(mark, pos) { |
656 | | - var ident = this._binary_data.slice(pos, pos + 5); |
657 | | - if (ident == this._EXIF_IDENT) { |
658 | | - this._exifHandler(mark, pos + 6); |
659 | | - } else { |
660 | | - /* Don't know about other idents */ |
661 | | - } |
662 | | - }; |
663 | | - |
664 | | - /* Handle exif segments */ |
665 | | - JpegMeta.JpegFile.prototype._exifHandler = function _exifHandler(mark, pos) { |
666 | | - if (this.exif !== undefined) { |
667 | | - throw new Error("Multiple JFIF segments found"); |
668 | | - } |
669 | | - |
670 | | - /* Parse this TIFF header */ |
671 | | - var endian; |
672 | | - var magic_field; |
673 | | - var ifd_offset; |
674 | | - var primary_ifd, exif_ifd, gps_ifd; |
675 | | - var endian_field = this._binary_data.slice(pos, pos + 2); |
676 | | - |
677 | | - /* Trivia: This 'I' is for Intel, the 'M' is for Motorola */ |
678 | | - if (endian_field === "II") { |
679 | | - endian = "<"; |
680 | | - } else if (endian_field === "MM") { |
681 | | - endian = ">"; |
682 | | - } else { |
683 | | - throw new Error("Malformed TIFF meta-data. Unknown endianess: " + endian_field); |
684 | | - } |
685 | | - |
686 | | - magic_field = JpegMeta.parseNum(endian, this._binary_data, pos + 2, 2); |
687 | | - |
688 | | - if (magic_field !== 42) { |
689 | | - throw new Error("Malformed TIFF meta-data. Bad magic: " + magic_field); |
690 | | - } |
691 | | - |
692 | | - ifd_offset = JpegMeta.parseNum(endian, this._binary_data, pos + 4, 4); |
693 | | - |
694 | | - /* Parse 0th IFD */ |
695 | | - this._parseIfd(endian, this._binary_data, pos, ifd_offset, this._tifftags, "tiff", "TIFF"); |
696 | | - |
697 | | - if (this.tiff.ExifIfdPointer) { |
698 | | - this._parseIfd(endian, this._binary_data, pos, this.tiff.ExifIfdPointer.value, this._exiftags, "exif", "Exif"); |
699 | | - } |
700 | | - |
701 | | - if (this.tiff.GPSInfoIfdPointer) { |
702 | | - this._parseIfd(endian, this._binary_data, pos, this.tiff.GPSInfoIfdPointer.value, this._gpstags, "gps", "GPS"); |
703 | | - if (this.gps.GPSLatitude) { |
704 | | - var latitude; |
705 | | - latitude = this.gps.GPSLatitude.value[0].asFloat() + |
706 | | - (1 / 60) * this.gps.GPSLatitude.value[1].asFloat() + |
707 | | - (1 / 3600) * this.gps.GPSLatitude.value[2].asFloat(); |
708 | | - if (this.gps.GPSLatitudeRef.value === "S") { |
709 | | - latitude = -latitude; |
710 | | - } |
711 | | - this.gps._addProperty("latitude", "Dec. Latitude", latitude); |
712 | | - } |
713 | | - if (this.gps.GPSLongitude) { |
714 | | - var longitude; |
715 | | - longitude = this.gps.GPSLongitude.value[0].asFloat() + |
716 | | - (1 / 60) * this.gps.GPSLongitude.value[1].asFloat() + |
717 | | - (1 / 3600) * this.gps.GPSLongitude.value[2].asFloat(); |
718 | | - if (this.gps.GPSLongitudeRef.value === "W") { |
719 | | - longitude = -longitude; |
720 | | - } |
721 | | - this.gps._addProperty("longitude", "Dec. Longitude", longitude); |
722 | | - } |
723 | | - } |
724 | | - }; |
725 | | - |
726 | | - /* JsJpegMeta ends here */ |
727 | | - |
728 | | - mw.util = $.extend( mw.util || {}, { |
729 | | - jpegmeta: function( fileReaderResult, fileName ) { |
730 | | - return new JpegMeta.JpegFile( fileReaderResult, fileName ); |
731 | | - } |
732 | | - } ); |
733 | | - |
734 | | -} )( jQuery, mediaWiki ); |
\ No newline at end of file |
Index: trunk/phase3/resources/mediawiki.libs/mediawiki.libs.jpegmeta.js |
— | — | @@ -0,0 +1,731 @@ |
| 2 | +/* This is JsJpegMeta 1.0, ported to MediaWiki ResourceLoader by Bryan Tong Minh */ |
| 3 | +/* The following lines where changed with respect to the original: 54, 625-627 */ |
| 4 | + |
| 5 | +(function( $ ) { |
| 6 | + |
| 7 | + /* JsJpegMeta starts here */ |
| 8 | + |
| 9 | + /* |
| 10 | + Copyright (c) 2009 Ben Leslie |
| 11 | + |
| 12 | + Permission is hereby granted, free of charge, to any person obtaining a copy |
| 13 | + of this software and associated documentation files (the "Software"), to deal |
| 14 | + in the Software without restriction, including without limitation the rights |
| 15 | + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 16 | + copies of the Software, and to permit persons to whom the Software is |
| 17 | + furnished to do so, subject to the following conditions: |
| 18 | + |
| 19 | + The above copyright notice and this permission notice shall be included in |
| 20 | + all copies or substantial portions of the Software. |
| 21 | + |
| 22 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 23 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 24 | + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 25 | + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 26 | + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 27 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 28 | + THE SOFTWARE. |
| 29 | + */ |
| 30 | + |
| 31 | + /* |
| 32 | + This JavaScript library is used to parse meta-data from files |
| 33 | + with mime-type image/jpeg. |
| 34 | + |
| 35 | + Include it with something like: |
| 36 | + |
| 37 | + <script type="text/javascript" src="jpegmeta.js"></script> |
| 38 | + |
| 39 | + This adds a single 'module' object called 'JpegMeta' to the global |
| 40 | + namespace. |
| 41 | + |
| 42 | + Public Functions |
| 43 | + ---------------- |
| 44 | + JpegMeta.parseNum - parse unsigned integers from binary data |
| 45 | + JpegMeta.parseSnum - parse signed integers from binary data |
| 46 | + |
| 47 | + Public Classes |
| 48 | + -------------- |
| 49 | + JpegMeta.Rational - A rational number class |
| 50 | + JpegMeta.JfifSegment |
| 51 | + JpegMeta.ExifSegment |
| 52 | + JpegMeta.JpegFile - Primary class for Javascript parsing |
| 53 | + */ |
| 54 | + |
| 55 | + var JpegMeta = {}; |
| 56 | + this.JpegMeta = JpegMeta; // I have no clue why I need this magic... -- Bryan |
| 57 | + |
| 58 | + /* |
| 59 | + parse an unsigned number of size bytes at offset in some binary string data. |
| 60 | + If endian |
| 61 | + is "<" parse the data as little endian, if endian |
| 62 | + is ">" parse as big-endian. |
| 63 | + */ |
| 64 | + JpegMeta.parseNum = function parseNum(endian, data, offset, size) { |
| 65 | + var i; |
| 66 | + var ret; |
| 67 | + var big_endian = (endian === ">"); |
| 68 | + if (offset === undefined) offset = 0; |
| 69 | + if (size === undefined) size = data.length - offset; |
| 70 | + for (big_endian ? i = offset : i = offset + size - 1; |
| 71 | + big_endian ? i < offset + size : i >= offset; |
| 72 | + big_endian ? i++ : i--) { |
| 73 | + ret <<= 8; |
| 74 | + ret += data.charCodeAt(i); |
| 75 | + } |
| 76 | + return ret; |
| 77 | + }; |
| 78 | + |
| 79 | + /* |
| 80 | + parse an signed number of size bytes at offset in some binary string data. |
| 81 | + If endian |
| 82 | + is "<" parse the data as little endian, if endian |
| 83 | + is ">" parse as big-endian. |
| 84 | + */ |
| 85 | + JpegMeta.parseSnum = function parseSnum(endian, data, offset, size) { |
| 86 | + var i; |
| 87 | + var ret; |
| 88 | + var neg; |
| 89 | + var big_endian = (endian === ">"); |
| 90 | + if (offset === undefined) offset = 0; |
| 91 | + if (size === undefined) size = data.length - offset; |
| 92 | + for (big_endian ? i = offset : i = offset + size - 1; |
| 93 | + big_endian ? i < offset + size : i >= offset; |
| 94 | + big_endian ? i++ : i--) { |
| 95 | + if (neg === undefined) { |
| 96 | + /* Negative if top bit is set */ |
| 97 | + neg = (data.charCodeAt(i) & 0x80) === 0x80; |
| 98 | + } |
| 99 | + ret <<= 8; |
| 100 | + /* If it is negative we invert the bits */ |
| 101 | + ret += neg ? ~data.charCodeAt(i) & 0xff: data.charCodeAt(i); |
| 102 | + } |
| 103 | + if (neg) { |
| 104 | + /* If it is negative we do two's complement */ |
| 105 | + ret += 1; |
| 106 | + ret *= -1; |
| 107 | + } |
| 108 | + return ret; |
| 109 | + }; |
| 110 | + |
| 111 | + /* Rational number class */ |
| 112 | + JpegMeta.Rational = function Rational(num, den) |
| 113 | + { |
| 114 | + this.num = num; |
| 115 | + this.den = den || 1; |
| 116 | + return this; |
| 117 | + }; |
| 118 | + |
| 119 | + /* Rational number methods */ |
| 120 | + JpegMeta.Rational.prototype.toString = function toString() { |
| 121 | + if (this.num === 0) { |
| 122 | + return "" + this.num |
| 123 | + } |
| 124 | + if (this.den === 1) { |
| 125 | + return "" + this.num; |
| 126 | + } |
| 127 | + if (this.num === 1) { |
| 128 | + return this.num + " / " + this.den; |
| 129 | + } |
| 130 | + return this.num / this.den; // + "/" + this.den; |
| 131 | + }; |
| 132 | + |
| 133 | + JpegMeta.Rational.prototype.asFloat = function asFloat() { |
| 134 | + return this.num / this.den; |
| 135 | + }; |
| 136 | + |
| 137 | + /* MetaGroup class */ |
| 138 | + JpegMeta.MetaGroup = function MetaGroup(fieldName, description) { |
| 139 | + this.fieldName = fieldName; |
| 140 | + this.description = description; |
| 141 | + this.metaProps = {}; |
| 142 | + return this; |
| 143 | + }; |
| 144 | + |
| 145 | + JpegMeta.MetaGroup.prototype._addProperty = function _addProperty(fieldName, description, value) { |
| 146 | + var property = new JpegMeta.MetaProp(fieldName, description, value); |
| 147 | + this[property.fieldName] = property; |
| 148 | + this.metaProps[property.fieldName] = property; |
| 149 | + }; |
| 150 | + |
| 151 | + JpegMeta.MetaGroup.prototype.toString = function toString() { |
| 152 | + return "[MetaGroup " + this.description + "]"; |
| 153 | + }; |
| 154 | + |
| 155 | + /* MetaProp class */ |
| 156 | + JpegMeta.MetaProp = function MetaProp(fieldName, description, value) { |
| 157 | + this.fieldName = fieldName; |
| 158 | + this.description = description; |
| 159 | + this.value = value; |
| 160 | + return this; |
| 161 | + }; |
| 162 | + |
| 163 | + JpegMeta.MetaProp.prototype.toString = function toString() { |
| 164 | + return "" + this.value; |
| 165 | + }; |
| 166 | + |
| 167 | + /* JpegFile class */ |
| 168 | + JpegMeta.JpegFile = function JpegFile(binary_data, filename) { |
| 169 | + /* Change this to EOI if we want to parse. */ |
| 170 | + var break_segment = this._SOS; |
| 171 | + |
| 172 | + this.metaGroups = {}; |
| 173 | + this._binary_data = binary_data; |
| 174 | + this.filename = filename; |
| 175 | + |
| 176 | + /* Go through and parse. */ |
| 177 | + var pos = 0; |
| 178 | + var pos_start_of_segment = 0; |
| 179 | + var delim; |
| 180 | + var mark; |
| 181 | + var _mark; |
| 182 | + var segsize; |
| 183 | + var headersize; |
| 184 | + var mark_code; |
| 185 | + var mark_fn; |
| 186 | + |
| 187 | + /* Check to see if this looks like a JPEG file */ |
| 188 | + if (this._binary_data.slice(0, 2) !== this._SOI_MARKER) { |
| 189 | + throw new Error("Doesn't look like a JPEG file. First two bytes are " + |
| 190 | + this._binary_data.charCodeAt(0) + "," + |
| 191 | + this._binary_data.charCodeAt(1) + "."); |
| 192 | + } |
| 193 | + |
| 194 | + pos += 2; |
| 195 | + |
| 196 | + while (pos < this._binary_data.length) { |
| 197 | + delim = this._binary_data.charCodeAt(pos++); |
| 198 | + mark = this._binary_data.charCodeAt(pos++); |
| 199 | + |
| 200 | + pos_start_of_segment = pos; |
| 201 | + |
| 202 | + if (delim != this._DELIM) { |
| 203 | + break; |
| 204 | + } |
| 205 | + |
| 206 | + if (mark === break_segment) { |
| 207 | + break; |
| 208 | + } |
| 209 | + |
| 210 | + headersize = JpegMeta.parseNum(">", this._binary_data, pos, 2); |
| 211 | + |
| 212 | + /* Find the end */ |
| 213 | + pos += headersize; |
| 214 | + while (pos < this._binary_data.length) { |
| 215 | + delim = this._binary_data.charCodeAt(pos++); |
| 216 | + if (delim == this._DELIM) { |
| 217 | + _mark = this._binary_data.charCodeAt(pos++); |
| 218 | + if (_mark != 0x0) { |
| 219 | + pos -= 2; |
| 220 | + break; |
| 221 | + } |
| 222 | + } |
| 223 | + } |
| 224 | + |
| 225 | + segsize = pos - pos_start_of_segment; |
| 226 | + |
| 227 | + if (this._markers[mark]) { |
| 228 | + mark_code = this._markers[mark][0]; |
| 229 | + mark_fn = this._markers[mark][1]; |
| 230 | + } else { |
| 231 | + mark_code = "UNKN"; |
| 232 | + mark_fn = undefined; |
| 233 | + } |
| 234 | + |
| 235 | + if (mark_fn) { |
| 236 | + this[mark_fn](mark, pos_start_of_segment + 2); |
| 237 | + } |
| 238 | + |
| 239 | + } |
| 240 | + |
| 241 | + if (this.general === undefined) { |
| 242 | + throw Error("Invalid JPEG file."); |
| 243 | + } |
| 244 | + |
| 245 | + return this; |
| 246 | + }; |
| 247 | + |
| 248 | + this.JpegMeta.JpegFile.prototype.toString = function () { |
| 249 | + return "[JpegFile " + this.filename + " " + |
| 250 | + this.general.type + " " + |
| 251 | + this.general.pixelWidth + "x" + |
| 252 | + this.general.pixelHeight + |
| 253 | + " Depth: " + this.general.depth + "]"; |
| 254 | + }; |
| 255 | + |
| 256 | + /* Some useful constants */ |
| 257 | + this.JpegMeta.JpegFile.prototype._SOI_MARKER = '\xff\xd8'; |
| 258 | + this.JpegMeta.JpegFile.prototype._DELIM = 0xff; |
| 259 | + this.JpegMeta.JpegFile.prototype._EOI = 0xd9; |
| 260 | + this.JpegMeta.JpegFile.prototype._SOS = 0xda; |
| 261 | + |
| 262 | + this.JpegMeta.JpegFile.prototype._sofHandler = function _sofHandler (mark, pos) { |
| 263 | + if (this.general !== undefined) { |
| 264 | + throw Error("Unexpected multiple-frame image"); |
| 265 | + } |
| 266 | + |
| 267 | + this._addMetaGroup("general", "General"); |
| 268 | + this.general._addProperty("depth", "Depth", JpegMeta.parseNum(">", this._binary_data, pos, 1)); |
| 269 | + this.general._addProperty("pixelHeight", "Pixel Height", JpegMeta.parseNum(">", this._binary_data, pos + 1, 2)); |
| 270 | + this.general._addProperty("pixelWidth", "Pixel Width",JpegMeta.parseNum(">", this._binary_data, pos + 3, 2)); |
| 271 | + this.general._addProperty("type", "Type", this._markers[mark][2]); |
| 272 | + }; |
| 273 | + |
| 274 | + /* JFIF idents */ |
| 275 | + this.JpegMeta.JpegFile.prototype._JFIF_IDENT = "JFIF\x00"; |
| 276 | + this.JpegMeta.JpegFile.prototype._JFXX_IDENT = "JFXX\x00"; |
| 277 | + |
| 278 | + /* EXIF idents */ |
| 279 | + this.JpegMeta.JpegFile.prototype._EXIF_IDENT = "Exif\x00"; |
| 280 | + |
| 281 | + /* TIFF types */ |
| 282 | + this.JpegMeta.JpegFile.prototype._types = { |
| 283 | + /* The format is identifier : ["type name", type_size_in_bytes ] */ |
| 284 | + 1 : ["BYTE", 1], |
| 285 | + 2 : ["ASCII", 1], |
| 286 | + 3 : ["SHORT", 2], |
| 287 | + 4 : ["LONG", 4], |
| 288 | + 5 : ["RATIONAL", 8], |
| 289 | + 6 : ["SBYTE", 1], |
| 290 | + 7 : ["UNDEFINED", 1], |
| 291 | + 8 : ["SSHORT", 2], |
| 292 | + 9 : ["SLONG", 4], |
| 293 | + 10 : ["SRATIONAL", 8], |
| 294 | + 11 : ["FLOAT", 4], |
| 295 | + 12 : ["DOUBLE", 8], |
| 296 | + }; |
| 297 | + |
| 298 | + this.JpegMeta.JpegFile.prototype._tifftags = { |
| 299 | + /* A. Tags relating to image data structure */ |
| 300 | + 256 : ["Image width", "ImageWidth"], |
| 301 | + 257 : ["Image height", "ImageLength"], |
| 302 | + 258 : ["Number of bits per component", "BitsPerSample"], |
| 303 | + 259 : ["Compression scheme", "Compression", |
| 304 | + {1 : "uncompressed", 6 : "JPEG compression" }], |
| 305 | + 262 : ["Pixel composition", "PhotmetricInerpretation", |
| 306 | + {2 : "RGB", 6 : "YCbCr"}], |
| 307 | + 274 : ["Orientation of image", "Orientation", |
| 308 | + /* FIXME: Check the mirror-image / reverse encoding and rotation */ |
| 309 | + {1 : "Normal", 2 : "Reverse?", |
| 310 | + 3 : "Upside-down", 4 : "Upside-down Reverse", |
| 311 | + 5 : "90 degree CW", 6 : "90 degree CW reverse", |
| 312 | + 7 : "90 degree CCW", 8 : "90 degree CCW reverse",}], |
| 313 | + 277 : ["Number of components", "SamplesPerPixel"], |
| 314 | + 284 : ["Image data arrangement", "PlanarConfiguration", |
| 315 | + {1 : "chunky format", 2 : "planar format"}], |
| 316 | + 530 : ["Subsampling ratio of Y to C", "YCbCrSubSampling"], |
| 317 | + 531 : ["Y and C positioning", "YCbCrPositioning", |
| 318 | + {1 : "centered", 2 : "co-sited"}], |
| 319 | + 282 : ["X Resolution", "XResolution"], |
| 320 | + 283 : ["Y Resolution", "YResolution"], |
| 321 | + 296 : ["Resolution Unit", "ResolutionUnit", |
| 322 | + {2 : "inches", 3 : "centimeters"}], |
| 323 | + /* B. Tags realting to recording offset */ |
| 324 | + 273 : ["Image data location", "StripOffsets"], |
| 325 | + 278 : ["Number of rows per strip", "RowsPerStrip"], |
| 326 | + 279 : ["Bytes per compressed strip", "StripByteCounts"], |
| 327 | + 513 : ["Offset to JPEG SOI", "JPEGInterchangeFormat"], |
| 328 | + 514 : ["Bytes of JPEG Data", "JPEGInterchangeFormatLength"], |
| 329 | + /* C. Tags relating to image data characteristics */ |
| 330 | + 301 : ["Transfer function", "TransferFunction"], |
| 331 | + 318 : ["White point chromaticity", "WhitePoint"], |
| 332 | + 319 : ["Chromaticities of primaries", "PrimaryChromaticities"], |
| 333 | + 529 : ["Color space transformation matrix coefficients", "YCbCrCoefficients"], |
| 334 | + 532 : ["Pair of black and white reference values", "ReferenceBlackWhite"], |
| 335 | + /* D. Other tags */ |
| 336 | + 306 : ["Date and time", "DateTime"], |
| 337 | + 270 : ["Image title", "ImageDescription"], |
| 338 | + 271 : ["Make", "Make"], |
| 339 | + 272 : ["Model", "Model"], |
| 340 | + 305 : ["Software", "Software"], |
| 341 | + 315 : ["Person who created the image", "Artist"], |
| 342 | + 316 : ["Host Computer", "HostComputer"], |
| 343 | + 33432 : ["Copyright holder", "Copyright"], |
| 344 | + |
| 345 | + 34665 : ["Exif tag", "ExifIfdPointer"], |
| 346 | + 34853 : ["GPS tag", "GPSInfoIfdPointer"], |
| 347 | + }; |
| 348 | + |
| 349 | + this.JpegMeta.JpegFile.prototype._exiftags = { |
| 350 | + /* Tag Support Levels (2) - 0th IFX Exif Private Tags */ |
| 351 | + /* A. Tags Relating to Version */ |
| 352 | + 36864 : ["Exif Version", "ExifVersion"], |
| 353 | + 40960 : ["FlashPix Version", "FlashpixVersion"], |
| 354 | + |
| 355 | + /* B. Tag Relating to Image Data Characteristics */ |
| 356 | + 40961 : ["Color Space", "ColorSpace"], |
| 357 | + |
| 358 | + /* C. Tags Relating to Image Configuration */ |
| 359 | + 37121 : ["Meaning of each component", "ComponentsConfiguration"], |
| 360 | + 37122 : ["Compressed Bits Per Pixel", "CompressedBitsPerPixel"], |
| 361 | + 40962 : ["Pixel X Dimension", "PixelXDimension"], |
| 362 | + 40963 : ["Pixel Y Dimension", "PixelYDimension"], |
| 363 | + |
| 364 | + /* D. Tags Relating to User Information */ |
| 365 | + 37500 : ["Manufacturer notes", "MakerNote"], |
| 366 | + 37510 : ["User comments", "UserComment"], |
| 367 | + |
| 368 | + /* E. Tag Relating to Related File Information */ |
| 369 | + 40964 : ["Related audio file", "RelatedSoundFile"], |
| 370 | + |
| 371 | + /* F. Tags Relating to Date and Time */ |
| 372 | + 36867 : ["Date Time Original", "DateTimeOriginal"], |
| 373 | + 36868 : ["Date Time Digitized", "DateTimeDigitized"], |
| 374 | + 37520 : ["DateTime subseconds", "SubSecTime"], |
| 375 | + 37521 : ["DateTimeOriginal subseconds", "SubSecTimeOriginal"], |
| 376 | + 37522 : ["DateTimeDigitized subseconds", "SubSecTimeDigitized"], |
| 377 | + |
| 378 | + /* G. Tags Relating to Picture-Taking Conditions */ |
| 379 | + 33434 : ["Exposure time", "ExposureTime"], |
| 380 | + 33437 : ["FNumber", "FNumber"], |
| 381 | + 34850 : ["Exposure program", "ExposureProgram"], |
| 382 | + 34852 : ["Spectral sensitivity", "SpectralSensitivity"], |
| 383 | + 34855 : ["ISO Speed Ratings", "ISOSpeedRatings"], |
| 384 | + 34856 : ["Optoelectric coefficient", "OECF"], |
| 385 | + 37377 : ["Shutter Speed", "ShutterSpeedValue"], |
| 386 | + 37378 : ["Aperture Value", "ApertureValue"], |
| 387 | + 37379 : ["Brightness", "BrightnessValue"], |
| 388 | + 37380 : ["Exposure Bias Value", "ExposureBiasValue"], |
| 389 | + 37381 : ["Max Aperture Value", "MaxApertureValue"], |
| 390 | + 37382 : ["Subject Distance", "SubjectDistance"], |
| 391 | + 37383 : ["Metering Mode", "MeteringMode"], |
| 392 | + 37384 : ["Light Source", "LightSource"], |
| 393 | + 37385 : ["Flash", "Flash"], |
| 394 | + 37386 : ["Focal Length", "FocalLength"], |
| 395 | + 37396 : ["Subject Area", "SubjectArea"], |
| 396 | + 41483 : ["Flash Energy", "FlashEnergy"], |
| 397 | + 41484 : ["Spatial Frequency Response", "SpatialFrequencyResponse"], |
| 398 | + 41486 : ["Focal Plane X Resolution", "FocalPlaneXResolution"], |
| 399 | + 41487 : ["Focal Plane Y Resolution", "FocalPlaneYResolution"], |
| 400 | + 41488 : ["Focal Plane Resolution Unit", "FocalPlaneResolutionUnit"], |
| 401 | + 41492 : ["Subject Location", "SubjectLocation"], |
| 402 | + 41493 : ["Exposure Index", "ExposureIndex"], |
| 403 | + 41495 : ["Sensing Method", "SensingMethod"], |
| 404 | + 41728 : ["File Source", "FileSource"], |
| 405 | + 41729 : ["Scene Type", "SceneType"], |
| 406 | + 41730 : ["CFA Pattern", "CFAPattern"], |
| 407 | + 41985 : ["Custom Rendered", "CustomRendered"], |
| 408 | + 41986 : ["Exposure Mode", "Exposure Mode"], |
| 409 | + 41987 : ["White Balance", "WhiteBalance"], |
| 410 | + 41988 : ["Digital Zoom Ratio", "DigitalZoomRatio"], |
| 411 | + 41990 : ["Scene Capture Type", "SceneCaptureType"], |
| 412 | + 41991 : ["Gain Control", "GainControl"], |
| 413 | + 41992 : ["Contrast", "Contrast"], |
| 414 | + 41993 : ["Saturation", "Saturation"], |
| 415 | + 41994 : ["Sharpness", "Sharpness"], |
| 416 | + 41995 : ["Device settings description", "DeviceSettingDescription"], |
| 417 | + 41996 : ["Subject distance range", "SubjectDistanceRange"], |
| 418 | + |
| 419 | + /* H. Other Tags */ |
| 420 | + 42016 : ["Unique image ID", "ImageUniqueID"], |
| 421 | + |
| 422 | + 40965 : ["Interoperability tag", "InteroperabilityIFDPointer"], |
| 423 | + }; |
| 424 | + |
| 425 | + this.JpegMeta.JpegFile.prototype._gpstags = { |
| 426 | + /* A. Tags Relating to GPS */ |
| 427 | + 0 : ["GPS tag version", "GPSVersionID"], |
| 428 | + 1 : ["North or South Latitude", "GPSLatitudeRef"], |
| 429 | + 2 : ["Latitude", "GPSLatitude"], |
| 430 | + 3 : ["East or West Longitude", "GPSLongitudeRef"], |
| 431 | + 4 : ["Longitude", "GPSLongitude"], |
| 432 | + 5 : ["Altitude reference", "GPSAltitudeRef"], |
| 433 | + 6 : ["Altitude", "GPSAltitude"], |
| 434 | + 7 : ["GPS time (atomic clock)", "GPSTimeStamp"], |
| 435 | + 8 : ["GPS satellites usedd for measurement", "GPSSatellites"], |
| 436 | + 9 : ["GPS receiver status", "GPSStatus"], |
| 437 | + 10 : ["GPS mesaurement mode", "GPSMeasureMode"], |
| 438 | + 11 : ["Measurement precision", "GPSDOP"], |
| 439 | + 12 : ["Speed unit", "GPSSpeedRef"], |
| 440 | + 13 : ["Speed of GPS receiver", "GPSSpeed"], |
| 441 | + 14 : ["Reference for direction of movement", "GPSTrackRef"], |
| 442 | + 15 : ["Direction of movement", "GPSTrack"], |
| 443 | + 16 : ["Reference for direction of image", "GPSImgDirectionRef"], |
| 444 | + 17 : ["Direction of image", "GPSImgDirection"], |
| 445 | + 18 : ["Geodetic survey data used", "GPSMapDatum"], |
| 446 | + 19 : ["Reference for latitude of destination", "GPSDestLatitudeRef"], |
| 447 | + 20 : ["Latitude of destination", "GPSDestLatitude"], |
| 448 | + 21 : ["Reference for longitude of destination", "GPSDestLongitudeRef"], |
| 449 | + 22 : ["Longitude of destination", "GPSDestLongitude"], |
| 450 | + 23 : ["Reference for bearing of destination", "GPSDestBearingRef"], |
| 451 | + 24 : ["Bearing of destination", "GPSDestBearing"], |
| 452 | + 25 : ["Reference for distance to destination", "GPSDestDistanceRef"], |
| 453 | + 26 : ["Distance to destination", "GPSDestDistance"], |
| 454 | + 27 : ["Name of GPS processing method", "GPSProcessingMethod"], |
| 455 | + 28 : ["Name of GPS area", "GPSAreaInformation"], |
| 456 | + 29 : ["GPS Date", "GPSDateStamp"], |
| 457 | + 30 : ["GPS differential correction", "GPSDifferential"], |
| 458 | + }; |
| 459 | + |
| 460 | + this.JpegMeta.JpegFile.prototype._markers = { |
| 461 | + /* Start Of Frame markers, non-differential, Huffman coding */ |
| 462 | + 0xc0: ["SOF0", "_sofHandler", "Baseline DCT"], |
| 463 | + 0xc1: ["SOF1", "_sofHandler", "Extended sequential DCT"], |
| 464 | + 0xc2: ["SOF2", "_sofHandler", "Progressive DCT"], |
| 465 | + 0xc3: ["SOF3", "_sofHandler", "Lossless (sequential)"], |
| 466 | + |
| 467 | + /* Start Of Frame markers, differential, Huffman coding */ |
| 468 | + 0xc5: ["SOF5", "_sofHandler", "Differential sequential DCT"], |
| 469 | + 0xc6: ["SOF6", "_sofHandler", "Differential progressive DCT"], |
| 470 | + 0xc7: ["SOF7", "_sofHandler", "Differential lossless (sequential)"], |
| 471 | + |
| 472 | + /* Start Of Frame markers, non-differential, arithmetic coding */ |
| 473 | + 0xc8: ["JPG", null, "Reserved for JPEG extensions"], |
| 474 | + 0xc9: ["SOF9", "_sofHandler", "Extended sequential DCT"], |
| 475 | + 0xca: ["SOF10", "_sofHandler", "Progressive DCT"], |
| 476 | + 0xcb: ["SOF11", "_sofHandler", "Lossless (sequential)"], |
| 477 | + |
| 478 | + /* Start Of Frame markers, differential, arithmetic coding */ |
| 479 | + 0xcd: ["SOF13", "_sofHandler", "Differential sequential DCT"], |
| 480 | + 0xce: ["SOF14", "_sofHandler", "Differential progressive DCT"], |
| 481 | + 0xcf: ["SOF15", "_sofHandler", "Differential lossless (sequential)"], |
| 482 | + |
| 483 | + /* Huffman table specification */ |
| 484 | + 0xc4: ["DHT", null, "Define Huffman table(s)"], |
| 485 | + 0xcc: ["DAC", null, "Define arithmetic coding conditioning(s)"], |
| 486 | + |
| 487 | + /* Restart interval termination" */ |
| 488 | + 0xd0: ["RST0", null, "Restart with modulo 8 count “0”"], |
| 489 | + 0xd1: ["RST1", null, "Restart with modulo 8 count “1”"], |
| 490 | + 0xd2: ["RST2", null, "Restart with modulo 8 count “2”"], |
| 491 | + 0xd3: ["RST3", null, "Restart with modulo 8 count “3”"], |
| 492 | + 0xd4: ["RST4", null, "Restart with modulo 8 count “4”"], |
| 493 | + 0xd5: ["RST5", null, "Restart with modulo 8 count “5”"], |
| 494 | + 0xd6: ["RST6", null, "Restart with modulo 8 count “6”"], |
| 495 | + 0xd7: ["RST7", null, "Restart with modulo 8 count “7”"], |
| 496 | + |
| 497 | + /* Other markers */ |
| 498 | + 0xd8: ["SOI", null, "Start of image"], |
| 499 | + 0xd9: ["EOI", null, "End of image"], |
| 500 | + 0xda: ["SOS", null, "Start of scan"], |
| 501 | + 0xdb: ["DQT", null, "Define quantization table(s)"], |
| 502 | + 0xdc: ["DNL", null, "Define number of lines"], |
| 503 | + 0xdd: ["DRI", null, "Define restart interval"], |
| 504 | + 0xde: ["DHP", null, "Define hierarchical progression"], |
| 505 | + 0xdf: ["EXP", null, "Expand reference component(s)"], |
| 506 | + 0xe0: ["APP0", "_app0Handler", "Reserved for application segments"], |
| 507 | + 0xe1: ["APP1", "_app1Handler"], |
| 508 | + 0xe2: ["APP2", null], |
| 509 | + 0xe3: ["APP3", null], |
| 510 | + 0xe4: ["APP4", null], |
| 511 | + 0xe5: ["APP5", null], |
| 512 | + 0xe6: ["APP6", null], |
| 513 | + 0xe7: ["APP7", null], |
| 514 | + 0xe8: ["APP8", null], |
| 515 | + 0xe9: ["APP9", null], |
| 516 | + 0xea: ["APP10", null], |
| 517 | + 0xeb: ["APP11", null], |
| 518 | + 0xec: ["APP12", null], |
| 519 | + 0xed: ["APP13", null], |
| 520 | + 0xee: ["APP14", null], |
| 521 | + 0xef: ["APP15", null], |
| 522 | + 0xf0: ["JPG0", null], /* Reserved for JPEG extensions */ |
| 523 | + 0xf1: ["JPG1", null], |
| 524 | + 0xf2: ["JPG2", null], |
| 525 | + 0xf3: ["JPG3", null], |
| 526 | + 0xf4: ["JPG4", null], |
| 527 | + 0xf5: ["JPG5", null], |
| 528 | + 0xf6: ["JPG6", null], |
| 529 | + 0xf7: ["JPG7", null], |
| 530 | + 0xf8: ["JPG8", null], |
| 531 | + 0xf9: ["JPG9", null], |
| 532 | + 0xfa: ["JPG10", null], |
| 533 | + 0xfb: ["JPG11", null], |
| 534 | + 0xfc: ["JPG12", null], |
| 535 | + 0xfd: ["JPG13", null], |
| 536 | + 0xfe: ["COM", null], /* Comment */ |
| 537 | + |
| 538 | + /* Reserved markers */ |
| 539 | + 0x01: ["JPG13", null], /* For temporary private use in arithmetic coding */ |
| 540 | + /* 02 -> bf are reserverd */ |
| 541 | + }; |
| 542 | + |
| 543 | + /* Private methods */ |
| 544 | + this.JpegMeta.JpegFile.prototype._addMetaGroup = function _addMetaGroup(name, description) { |
| 545 | + var group = new JpegMeta.MetaGroup(name, description); |
| 546 | + this[group.fieldName] = group; |
| 547 | + this.metaGroups[group.fieldName] = group; |
| 548 | + return group; |
| 549 | + }; |
| 550 | + |
| 551 | + this.JpegMeta.JpegFile.prototype._parseIfd = function _parseIfd(endian, _binary_data, base, ifd_offset, tags, name, description) { |
| 552 | + var num_fields = JpegMeta.parseNum(endian, _binary_data, base + ifd_offset, 2); |
| 553 | + /* Per tag variables */ |
| 554 | + var i, j; |
| 555 | + var tag_base; |
| 556 | + var tag_field; |
| 557 | + var type, type_field, type_size; |
| 558 | + var num_values; |
| 559 | + var value_offset; |
| 560 | + var value; |
| 561 | + var _val; |
| 562 | + var num; |
| 563 | + var den; |
| 564 | + |
| 565 | + var group; |
| 566 | + |
| 567 | + group = this._addMetaGroup(name, description); |
| 568 | + |
| 569 | + for (var i = 0; i < num_fields; i++) { |
| 570 | + /* parse the field */ |
| 571 | + tag_base = base + ifd_offset + 2 + (i * 12); |
| 572 | + tag_field = JpegMeta.parseNum(endian, _binary_data, tag_base, 2); |
| 573 | + type_field = JpegMeta.parseNum(endian, _binary_data, tag_base + 2, 2); |
| 574 | + num_values = JpegMeta.parseNum(endian, _binary_data, tag_base + 4, 4); |
| 575 | + value_offset = JpegMeta.parseNum(endian, _binary_data, tag_base + 8, 4); |
| 576 | + if (this._types[type_field] === undefined) { |
| 577 | + continue; |
| 578 | + } |
| 579 | + type = this._types[type_field][0]; |
| 580 | + type_size = this._types[type_field][1]; |
| 581 | + |
| 582 | + if (type_size * num_values <= 4) { |
| 583 | + /* Data is in-line */ |
| 584 | + value_offset = tag_base + 8; |
| 585 | + } else { |
| 586 | + value_offset = base + value_offset; |
| 587 | + } |
| 588 | + |
| 589 | + /* Read the value */ |
| 590 | + if (type == "UNDEFINED") { |
| 591 | + value = _binary_data.slice(value_offset, value_offset + num_values); |
| 592 | + } else if (type == "ASCII") { |
| 593 | + value = _binary_data.slice(value_offset, value_offset + num_values); |
| 594 | + value = value.split('\x00')[0]; |
| 595 | + /* strip trail nul */ |
| 596 | + } else { |
| 597 | + value = new Array(); |
| 598 | + for (j = 0; j < num_values; j++, value_offset += type_size) { |
| 599 | + if (type == "BYTE" || type == "SHORT" || type == "LONG") { |
| 600 | + value.push(JpegMeta.parseNum(endian, _binary_data, value_offset, type_size)); |
| 601 | + } |
| 602 | + if (type == "SBYTE" || type == "SSHORT" || type == "SLONG") { |
| 603 | + value.push(JpegMeta.parseSnum(endian, _binary_data, value_offset, type_size)); |
| 604 | + } |
| 605 | + if (type == "RATIONAL") { |
| 606 | + num = JpegMeta.parseNum(endian, _binary_data, value_offset, 4); |
| 607 | + den = JpegMeta.parseNum(endian, _binary_data, value_offset + 4, 4); |
| 608 | + value.push(new JpegMeta.Rational(num, den)); |
| 609 | + } |
| 610 | + if (type == "SRATIONAL") { |
| 611 | + num = JpegMeta.parseSnum(endian, _binary_data, value_offset, 4); |
| 612 | + den = JpegMeta.parseSnum(endian, _binary_data, value_offset + 4, 4); |
| 613 | + value.push(new JpegMeta.Rational(num, den)); |
| 614 | + } |
| 615 | + value.push(); |
| 616 | + } |
| 617 | + if (num_values === 1) { |
| 618 | + value = value[0]; |
| 619 | + } |
| 620 | + } |
| 621 | + if (tags[tag_field] !== undefined) { |
| 622 | + group._addProperty(tags[tag_field][1], tags[tag_field][0], value); |
| 623 | + } |
| 624 | + } |
| 625 | + }; |
| 626 | + |
| 627 | + this.JpegMeta.JpegFile.prototype._jfifHandler = function _jfifHandler(mark, pos) { |
| 628 | + if (this.jfif !== undefined) { |
| 629 | + throw Error("Multiple JFIF segments found"); |
| 630 | + } |
| 631 | + this._addMetaGroup("jfif", "JFIF"); |
| 632 | + this.jfif._addProperty("version_major", "Version Major", this._binary_data.charCodeAt(pos + 5)); |
| 633 | + this.jfif._addProperty("version_minor", "Version Minor", this._binary_data.charCodeAt(pos + 6)); |
| 634 | + this.jfif._addProperty("version", "JFIF Version", this.jfif.version_major.value + "." + this.jfif.version_minor.value); |
| 635 | + this.jfif._addProperty("units", "Density Unit", this._binary_data.charCodeAt(pos + 7)); |
| 636 | + this.jfif._addProperty("Xdensity", "X density", JpegMeta.parseNum(">", this._binary_data, pos + 8, 2)); |
| 637 | + this.jfif._addProperty("Ydensity", "Y Density", JpegMeta.parseNum(">", this._binary_data, pos + 10, 2)); |
| 638 | + this.jfif._addProperty("Xthumbnail", "X Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 12, 1)); |
| 639 | + this.jfif._addProperty("Ythumbnail", "Y Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 13, 1)); |
| 640 | + }; |
| 641 | + |
| 642 | + /* Handle app0 segments */ |
| 643 | + this.JpegMeta.JpegFile.prototype._app0Handler = function app0Handler(mark, pos) { |
| 644 | + var ident = this._binary_data.slice(pos, pos + 5); |
| 645 | + if (ident == this._JFIF_IDENT) { |
| 646 | + this._jfifHandler(mark, pos); |
| 647 | + } else if (ident == this._JFXX_IDENT) { |
| 648 | + /* Don't handle JFXX Ident yet */ |
| 649 | + } else { |
| 650 | + /* Don't know about other idents */ |
| 651 | + } |
| 652 | + }; |
| 653 | + |
| 654 | + /* Handle app1 segments */ |
| 655 | + this.JpegMeta.JpegFile.prototype._app1Handler = function _app1Handler(mark, pos) { |
| 656 | + var ident = this._binary_data.slice(pos, pos + 5); |
| 657 | + if (ident == this._EXIF_IDENT) { |
| 658 | + this._exifHandler(mark, pos + 6); |
| 659 | + } else { |
| 660 | + /* Don't know about other idents */ |
| 661 | + } |
| 662 | + }; |
| 663 | + |
| 664 | + /* Handle exif segments */ |
| 665 | + JpegMeta.JpegFile.prototype._exifHandler = function _exifHandler(mark, pos) { |
| 666 | + if (this.exif !== undefined) { |
| 667 | + throw new Error("Multiple JFIF segments found"); |
| 668 | + } |
| 669 | + |
| 670 | + /* Parse this TIFF header */ |
| 671 | + var endian; |
| 672 | + var magic_field; |
| 673 | + var ifd_offset; |
| 674 | + var primary_ifd, exif_ifd, gps_ifd; |
| 675 | + var endian_field = this._binary_data.slice(pos, pos + 2); |
| 676 | + |
| 677 | + /* Trivia: This 'I' is for Intel, the 'M' is for Motorola */ |
| 678 | + if (endian_field === "II") { |
| 679 | + endian = "<"; |
| 680 | + } else if (endian_field === "MM") { |
| 681 | + endian = ">"; |
| 682 | + } else { |
| 683 | + throw new Error("Malformed TIFF meta-data. Unknown endianess: " + endian_field); |
| 684 | + } |
| 685 | + |
| 686 | + magic_field = JpegMeta.parseNum(endian, this._binary_data, pos + 2, 2); |
| 687 | + |
| 688 | + if (magic_field !== 42) { |
| 689 | + throw new Error("Malformed TIFF meta-data. Bad magic: " + magic_field); |
| 690 | + } |
| 691 | + |
| 692 | + ifd_offset = JpegMeta.parseNum(endian, this._binary_data, pos + 4, 4); |
| 693 | + |
| 694 | + /* Parse 0th IFD */ |
| 695 | + this._parseIfd(endian, this._binary_data, pos, ifd_offset, this._tifftags, "tiff", "TIFF"); |
| 696 | + |
| 697 | + if (this.tiff.ExifIfdPointer) { |
| 698 | + this._parseIfd(endian, this._binary_data, pos, this.tiff.ExifIfdPointer.value, this._exiftags, "exif", "Exif"); |
| 699 | + } |
| 700 | + |
| 701 | + if (this.tiff.GPSInfoIfdPointer) { |
| 702 | + this._parseIfd(endian, this._binary_data, pos, this.tiff.GPSInfoIfdPointer.value, this._gpstags, "gps", "GPS"); |
| 703 | + if (this.gps.GPSLatitude) { |
| 704 | + var latitude; |
| 705 | + latitude = this.gps.GPSLatitude.value[0].asFloat() + |
| 706 | + (1 / 60) * this.gps.GPSLatitude.value[1].asFloat() + |
| 707 | + (1 / 3600) * this.gps.GPSLatitude.value[2].asFloat(); |
| 708 | + if (this.gps.GPSLatitudeRef.value === "S") { |
| 709 | + latitude = -latitude; |
| 710 | + } |
| 711 | + this.gps._addProperty("latitude", "Dec. Latitude", latitude); |
| 712 | + } |
| 713 | + if (this.gps.GPSLongitude) { |
| 714 | + var longitude; |
| 715 | + longitude = this.gps.GPSLongitude.value[0].asFloat() + |
| 716 | + (1 / 60) * this.gps.GPSLongitude.value[1].asFloat() + |
| 717 | + (1 / 3600) * this.gps.GPSLongitude.value[2].asFloat(); |
| 718 | + if (this.gps.GPSLongitudeRef.value === "W") { |
| 719 | + longitude = -longitude; |
| 720 | + } |
| 721 | + this.gps._addProperty("longitude", "Dec. Longitude", longitude); |
| 722 | + } |
| 723 | + } |
| 724 | + }; |
| 725 | + |
| 726 | + /* JsJpegMeta ends here */ |
| 727 | + |
| 728 | + mw.libs.jpegmeta = function( fileReaderResult, fileName ) { |
| 729 | + return new JpegMeta.JpegFile( fileReaderResult, fileName ); |
| 730 | + }; |
| 731 | + |
| 732 | +} )( jQuery ); |
\ No newline at end of file |
Property changes on: trunk/phase3/resources/mediawiki.libs/mediawiki.libs.jpegmeta.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 733 | + native |