r89335 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r89334‎ | r89335 | r89336 >
Date:13:44, 2 June 2011
Author:hashar
Status:ok
Tags:
Comment:
properly move the jpegmeta.js file from util to libs.

Follow up r89083 (code change)
Fix r89084 (file move without history, reverted by r89334)
Modified paths:
  • /trunk/phase3/resources/mediawiki.libs/mediawiki.libs.jpegmeta.js (added) (history)
  • /trunk/phase3/resources/mediawiki.util/mediawiki.util.jpegmeta.js (deleted) (history)

Diff [purge]

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
1733 + native

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r89083Introducing mw.libs, moving JpegMeta into it....krinkle03:13, 29 May 2011
r89084Fix r89083: Actually add the directorykrinkle03:23, 29 May 2011
r89334revert r89084 (file moved without keeping history)hashar13:40, 2 June 2011

Status & tagging log