[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/resources/src/mediawiki.libs/ -> mediawiki.libs.jpegmeta.js (source)

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


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1