vendor: 30,092 bytes, lines 1-805
1(function () { 2 3 var debug = false; 4 5 var root = this; 6 7 var EXIF = function (obj) { 8 if (obj instanceof EXIF) return obj; 9 if (!(this instanceof EXIF)) return new EXIF(obj); 10 this.EXIFwrapped = obj; 11 }; 12 13 if (typeof exports !== 'undefined') { 14 if (typeof module !== 'undefined' && module.exports) { 15 exports = module.exports = EXIF; 16 } 17 exports.EXIF = EXIF; 18 } else { 19 root.EXIF = EXIF; 20 } 21 22 var ExifTags = EXIF.Tags = { 23 24 // version tags 25 0x9000: "ExifVersion", // EXIF version 26 0xA000: "FlashpixVersion", // Flashpix format version 27 28 // colorspace tags 29 0xA001: "ColorSpace", // Color space information tag 30 31 // image configuration 32 0xA002: "PixelXDimension", // Valid width of meaningful image 33 0xA003: "PixelYDimension", // Valid height of meaningful image 34 0x9101: "ComponentsConfiguration", // Information about channels 35 0x9102: "CompressedBitsPerPixel", // Compressed bits per pixel 36 37 // user information 38 0x927C: "MakerNote", // Any desired information written by the manufacturer 39 0x9286: "UserComment", // Comments by user 40 41 // related file 42 0xA004: "RelatedSoundFile", // Name of related sound file 43 44 // date and time 45 0x9003: "DateTimeOriginal", // Date and time when the original image was generated 46 0x9004: "DateTimeDigitized", // Date and time when the image was stored digitally 47 0x9290: "SubsecTime", // Fractions of seconds for DateTime 48 0x9291: "SubsecTimeOriginal", // Fractions of seconds for DateTimeOriginal 49 0x9292: "SubsecTimeDigitized", // Fractions of seconds for DateTimeDigitized 50 51 // picture-taking conditions 52 0x829A: "ExposureTime", // Exposure time (in seconds) 53 0x829D: "FNumber", // F number 54 0x8822: "ExposureProgram", // Exposure program 55 0x8824: "SpectralSensitivity", // Spectral sensitivity 56 0x8827: "ISOSpeedRatings", // ISO speed rating 57 0x8828: "OECF", // Optoelectric conversion factor 58 0x9201: "ShutterSpeedValue", // Shutter speed 59 0x9202: "ApertureValue", // Lens aperture 60 0x9203: "BrightnessValue", // Value of brightness 61 0x9204: "ExposureBias", // Exposure bias 62 0x9205: "MaxApertureValue", // Smallest F number of lens 63 0x9206: "SubjectDistance", // Distance to subject in meters 64 0x9207: "MeteringMode", // Metering mode 65 0x9208: "LightSource", // Kind of light source 66 0x9209: "Flash", // Flash status 67 0x9214: "SubjectArea", // Location and area of main subject 68 0x920A: "FocalLength", // Focal length of the lens in mm 69 0xA20B: "FlashEnergy", // Strobe energy in BCPS 70 0xA20C: "SpatialFrequencyResponse", // 71 0xA20E: "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit 72 0xA20F: "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit 73 0xA210: "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution 74 0xA214: "SubjectLocation", // Location of subject in image 75 0xA215: "ExposureIndex", // Exposure index selected on camera 76 0xA217: "SensingMethod", // Image sensor type 77 0xA300: "FileSource", // Image source (3 == DSC) 78 0xA301: "SceneType", // Scene type (1 == directly photographed) 79 0xA302: "CFAPattern", // Color filter array geometric pattern 80 0xA401: "CustomRendered", // Special processing 81 0xA402: "ExposureMode", // Exposure mode 82 0xA403: "WhiteBalance", // 1 = auto white balance, 2 = manual 83 0xA404: "DigitalZoomRation", // Digital zoom ratio 84 0xA405: "FocalLengthIn35mmFilm", // Equivalent foacl length assuming 35mm film camera (in mm) 85 0xA406: "SceneCaptureType", // Type of scene 86 0xA407: "GainControl", // Degree of overall image gain adjustment 87 0xA408: "Contrast", // Direction of contrast processing applied by camera 88 0xA409: "Saturation", // Direction of saturation processing applied by camera 89 0xA40A: "Sharpness", // Direction of sharpness processing applied by camera 90 0xA40B: "DeviceSettingDescription", // 91 0xA40C: "SubjectDistanceRange", // Distance to subject 92 93 // other tags 94 0xA005: "InteroperabilityIFDPointer", 95 0xA420: "ImageUniqueID" // Identifier assigned uniquely to each image 96 }; 97 98 var TiffTags = EXIF.TiffTags = { 99 0x0100: "ImageWidth", 100 0x0101: "ImageHeight", 101 0x8769: "ExifIFDPointer", 102 0x8825: "GPSInfoIFDPointer", 103 0xA005: "InteroperabilityIFDPointer", 104 0x0102: "BitsPerSample", 105 0x0103: "Compression", 106 0x0106: "PhotometricInterpretation", 107 0x0112: "Orientation", 108 0x0115: "SamplesPerPixel", 109 0x011C: "PlanarConfiguration", 110 0x0212: "YCbCrSubSampling", 111 0x0213: "YCbCrPositioning", 112 0x011A: "XResolution", 113 0x011B: "YResolution", 114 0x0128: "ResolutionUnit", 115 0x0111: "StripOffsets", 116 0x0116: "RowsPerStrip", 117 0x0117: "StripByteCounts", 118 0x0201: "JPEGInterchangeFormat", 119 0x0202: "JPEGInterchangeFormatLength", 120 0x012D: "TransferFunction", 121 0x013E: "WhitePoint", 122 0x013F: "PrimaryChromaticities", 123 0x0211: "YCbCrCoefficients", 124 0x0214: "ReferenceBlackWhite", 125 0x0132: "DateTime", 126 0x010E: "ImageDescription", 127 0x010F: "Make", 128 0x0110: "Model", 129 0x0131: "Software", 130 0x013B: "Artist", 131 0x8298: "Copyright" 132 }; 133 134 var GPSTags = EXIF.GPSTags = { 135 0x0000: "GPSVersionID", 136 0x0001: "GPSLatitudeRef", 137 0x0002: "GPSLatitude", 138 0x0003: "GPSLongitudeRef", 139 0x0004: "GPSLongitude", 140 0x0005: "GPSAltitudeRef", 141 0x0006: "GPSAltitude", 142 0x0007: "GPSTimeStamp", 143 0x0008: "GPSSatellites", 144 0x0009: "GPSStatus", 145 0x000A: "GPSMeasureMode", 146 0x000B: "GPSDOP", 147 0x000C: "GPSSpeedRef", 148 0x000D: "GPSSpeed", 149 0x000E: "GPSTrackRef", 150 0x000F: "GPSTrack", 151 0x0010: "GPSImgDirectionRef", 152 0x0011: "GPSImgDirection", 153 0x0012: "GPSMapDatum", 154 0x0013: "GPSDestLatitudeRef", 155 0x0014: "GPSDestLatitude", 156 0x0015: "GPSDestLongitudeRef", 157 0x0016: "GPSDestLongitude", 158 0x0017: "GPSDestBearingRef", 159 0x0018: "GPSDestBearing", 160 0x0019: "GPSDestDistanceRef", 161 0x001A: "GPSDestDistance", 162 0x001B: "GPSProcessingMethod", 163 0x001C: "GPSAreaInformation", 164 0x001D: "GPSDateStamp", 165 0x001E: "GPSDifferential" 166 }; 167 168 var StringValues = EXIF.StringValues = { 169 ExposureProgram: { 170 0: "Not defined", 171 1: "Manual", 172 2: "Normal program", 173 3: "Aperture priority", 174 4: "Shutter priority", 175 5: "Creative program", 176 6: "Action program", 177 7: "Portrait mode", 178 8: "Landscape mode" 179 }, 180 MeteringMode: { 181 0: "Unknown", 182 1: "Average", 183 2: "CenterWeightedAverage", 184 3: "Spot", 185 4: "MultiSpot", 186 5: "Pattern", 187 6: "Partial", 188 255: "Other" 189 }, 190 LightSource: { 191 0: "Unknown", 192 1: "Daylight", 193 2: "Fluorescent", 194 3: "Tungsten (incandescent light)", 195 4: "Flash", 196 9: "Fine weather", 197 10: "Cloudy weather", 198 11: "Shade", 199 12: "Daylight fluorescent (D 5700 - 7100K)", 200 13: "Day white fluorescent (N 4600 - 5400K)", 201 14: "Cool white fluorescent (W 3900 - 4500K)", 202 15: "White fluorescent (WW 3200 - 3700K)", 203 17: "Standard light A", 204 18: "Standard light B", 205 19: "Standard light C", 206 20: "D55", 207 21: "D65", 208 22: "D75", 209 23: "D50", 210 24: "ISO studio tungsten", 211 255: "Other" 212 }, 213 Flash: { 214 0x0000: "Flash did not fire", 215 0x0001: "Flash fired", 216 0x0005: "Strobe return light not detected", 217 0x0007: "Strobe return light detected", 218 0x0009: "Flash fired, compulsory flash mode", 219 0x000D: "Flash fired, compulsory flash mode, return light not detected", 220 0x000F: "Flash fired, compulsory flash mode, return light detected", 221 0x0010: "Flash did not fire, compulsory flash mode", 222 0x0018: "Flash did not fire, auto mode", 223 0x0019: "Flash fired, auto mode", 224 0x001D: "Flash fired, auto mode, return light not detected", 225 0x001F: "Flash fired, auto mode, return light detected", 226 0x0020: "No flash function", 227 0x0041: "Flash fired, red-eye reduction mode", 228 0x0045: "Flash fired, red-eye reduction mode, return light not detected", 229 0x0047: "Flash fired, red-eye reduction mode, return light detected", 230 0x0049: "Flash fired, compulsory flash mode, red-eye reduction mode", 231 0x004D: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected", 232 0x004F: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected", 233 0x0059: "Flash fired, auto mode, red-eye reduction mode", 234 0x005D: "Flash fired, auto mode, return light not detected, red-eye reduction mode", 235 0x005F: "Flash fired, auto mode, return light detected, red-eye reduction mode" 236 }, 237 SensingMethod: { 238 1: "Not defined", 239 2: "One-chip color area sensor", 240 3: "Two-chip color area sensor", 241 4: "Three-chip color area sensor", 242 5: "Color sequential area sensor", 243 7: "Trilinear sensor", 244 8: "Color sequential linear sensor" 245 }, 246 SceneCaptureType: { 247 0: "Standard", 248 1: "Landscape", 249 2: "Portrait", 250 3: "Night scene" 251 }, 252 SceneType: { 253 1: "Directly photographed" 254 }, 255 CustomRendered: { 256 0: "Normal process", 257 1: "Custom process" 258 }, 259 WhiteBalance: { 260 0: "Auto white balance", 261 1: "Manual white balance" 262 }, 263 GainControl: { 264 0: "None", 265 1: "Low gain up", 266 2: "High gain up", 267 3: "Low gain down", 268 4: "High gain down" 269 }, 270 Contrast: { 271 0: "Normal", 272 1: "Soft", 273 2: "Hard" 274 }, 275 Saturation: { 276 0: "Normal", 277 1: "Low saturation", 278 2: "High saturation" 279 }, 280 Sharpness: { 281 0: "Normal", 282 1: "Soft", 283 2: "Hard" 284 }, 285 SubjectDistanceRange: { 286 0: "Unknown", 287 1: "Macro", 288 2: "Close view", 289 3: "Distant view" 290 }, 291 FileSource: { 292 3: "DSC" 293 }, 294 295 Components: { 296 0: "", 297 1: "Y", 298 2: "Cb", 299 3: "Cr", 300 4: "R", 301 5: "G", 302 6: "B" 303 } 304 }; 305 306 function addEvent(element, event, handler) { 307 if (element.addEventListener) { 308 element.addEventListener(event, handler, false); 309 } else if (element.attachEvent) { 310 element.attachEvent("on" + event, handler); 311 } 312 } 313 314 function imageHasData(img) { 315 return !!(img.exifdata); 316 } 317 318 319 function base64ToArrayBuffer(base64, contentType) { 320 contentType = contentType || base64.match(/^data\:([^\;]+)\;base64,/mi)[1] || ''; // e.g. 'data:image/jpeg;base64,...' => 'image/jpeg' 321 base64 = base64.replace(/^data\:([^\;]+)\;base64,/gmi, ''); 322 var binary = atob(base64); 323 var len = binary.length; 324 var buffer = new ArrayBuffer(len); 325 var view = new Uint8Array(buffer); 326 for (var i = 0; i < len; i++) { 327 view[i] = binary.charCodeAt(i); 328 } 329 return buffer; 330 } 331 332 function objectURLToBlob(url, callback) { 333 var http = new XMLHttpRequest(); 334 http.open("GET", url, true); 335 http.responseType = "blob"; 336 http.onload = function (e) { 337 if (this.status == 200 || this.status === 0) { 338 callback(this.response); 339 } 340 }; 341 http.send(); 342 } 343 344 function getImageData(img, callback) { 345 function handleBinaryFile(binFile) { 346 var data = findEXIFinJPEG(binFile); 347 var iptcdata = findIPTCinJPEG(binFile); 348 img.exifdata = data || {}; 349 img.iptcdata = iptcdata || {}; 350 if (callback) { 351 callback.call(img); 352 } 353 } 354 355 if (img.src) { 356 if (/^data\:/i.test(img.src)) { // Data URI 357 var arrayBuffer = base64ToArrayBuffer(img.src); 358 handleBinaryFile(arrayBuffer); 359 360 } else if (/^blob\:/i.test(img.src)) { // Object URL 361 var fileReader = new FileReader(); 362 fileReader.onload = function (e) { 363 handleBinaryFile(e.target.result); 364 }; 365 objectURLToBlob(img.src, function (blob) { 366 fileReader.readAsArrayBuffer(blob); 367 }); 368 } else { 369 var http = new XMLHttpRequest(); 370 http.onload = function () { 371 if (this.status == 200 || this.status === 0) { 372 handleBinaryFile(http.response); 373 } else { 374 throw "Could not load image"; 375 } 376 http = null; 377 }; 378 http.open("GET", img.src, true); 379 http.responseType = "arraybuffer"; 380 http.send(null); 381 } 382 } else if (window.FileReader && (img instanceof window.Blob || img instanceof window.File)) { 383 var fileReader = new FileReader(); 384 fileReader.onload = function (e) { 385 if (debug) console.log("Got file of length " + e.target.result.byteLength); 386 handleBinaryFile(e.target.result); 387 }; 388 389 fileReader.readAsArrayBuffer(img); 390 } 391 } 392 393 function findEXIFinJPEG(file) { 394 var dataView = new DataView(file); 395 396 if (debug) console.log("Got file of length " + file.byteLength); 397 if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) { 398 if (debug) console.log("Not a valid JPEG"); 399 return false; // not a valid jpeg 400 } 401 402 var offset = 2, 403 length = file.byteLength, 404 marker; 405 406 while (offset < length) { 407 if (dataView.getUint8(offset) != 0xFF) { 408 if (debug) console.log("Not a valid marker at offset " + offset + ", found: " + dataView.getUint8(offset)); 409 return false; // not a valid marker, something is wrong 410 } 411 412 marker = dataView.getUint8(offset + 1); 413 if (debug) console.log(marker); 414 415 // we could implement handling for other markers here, 416 // but we're only looking for 0xFFE1 for EXIF data 417 418 if (marker == 225) { 419 if (debug) console.log("Found 0xFFE1 marker"); 420 421 return readEXIFData(dataView, offset + 4, dataView.getUint16(offset + 2) - 2); 422 423 // offset += 2 + file.getShortAt(offset+2, true); 424 425 } else { 426 offset += 2 + dataView.getUint16(offset + 2); 427 } 428 429 } 430 431 } 432 433 function findIPTCinJPEG(file) { 434 var dataView = new DataView(file); 435 436 if (debug) console.log("Got file of length " + file.byteLength); 437 if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) { 438 if (debug) console.log("Not a valid JPEG"); 439 return false; // not a valid jpeg 440 } 441 442 var offset = 2, 443 length = file.byteLength; 444 445 446 var isFieldSegmentStart = function (dataView, offset) { 447 return ( 448 dataView.getUint8(offset) === 0x38 && 449 dataView.getUint8(offset + 1) === 0x42 && 450 dataView.getUint8(offset + 2) === 0x49 && 451 dataView.getUint8(offset + 3) === 0x4D && 452 dataView.getUint8(offset + 4) === 0x04 && 453 dataView.getUint8(offset + 5) === 0x04 454 ); 455 }; 456 457 while (offset < length) { 458 459 if (isFieldSegmentStart(dataView, offset)) { 460 461 // Get the length of the name header (which is padded to an even number of bytes) 462 var nameHeaderLength = dataView.getUint8(offset + 7); 463 if (nameHeaderLength % 2 !== 0) nameHeaderLength += 1; 464 // Check for pre photoshop 6 format 465 if (nameHeaderLength === 0) { 466 // Always 4 467 nameHeaderLength = 4; 468 } 469 470 var startOffset = offset + 8 + nameHeaderLength; 471 var sectionLength = dataView.getUint16(offset + 6 + nameHeaderLength); 472 473 return readIPTCData(file, startOffset, sectionLength); 474 475 break; 476 477 } 478 479 480 // Not the marker, continue searching 481 offset++; 482 483 } 484 485 } 486 487 var IptcFieldMap = { 488 0x78: 'caption', 489 0x6E: 'credit', 490 0x19: 'keywords', 491 0x37: 'dateCreated', 492 0x50: 'byline', 493 0x55: 'bylineTitle', 494 0x7A: 'captionWriter', 495 0x69: 'headline', 496 0x74: 'copyright', 497 0x0F: 'category' 498 }; 499 500 function readIPTCData(file, startOffset, sectionLength) { 501 var dataView = new DataView(file); 502 var data = {}; 503 var fieldValue, fieldName, dataSize, segmentType, segmentSize; 504 var segmentStartPos = startOffset; 505 while (segmentStartPos < startOffset + sectionLength) { 506 if (dataView.getUint8(segmentStartPos) === 0x1C && dataView.getUint8(segmentStartPos + 1) === 0x02) { 507 segmentType = dataView.getUint8(segmentStartPos + 2); 508 if (segmentType in IptcFieldMap) { 509 dataSize = dataView.getInt16(segmentStartPos + 3); 510 segmentSize = dataSize + 5; 511 fieldName = IptcFieldMap[segmentType]; 512 fieldValue = getStringFromDB(dataView, segmentStartPos + 5, dataSize); 513 // Check if we already stored a value with this name 514 if (data.hasOwnProperty(fieldName)) { 515 // Value already stored with this name, create multivalue field 516 if (data[fieldName] instanceof Array) { 517 data[fieldName].push(fieldValue); 518 } 519 else { 520 data[fieldName] = [data[fieldName], fieldValue]; 521 } 522 } 523 else { 524 data[fieldName] = fieldValue; 525 } 526 } 527 528 } 529 segmentStartPos++; 530 } 531 return data; 532 } 533 534 535 function readTags(file, tiffStart, dirStart, strings, bigEnd) { 536 var entries = file.getUint16(dirStart, !bigEnd), 537 tags = {}, 538 entryOffset, tag, 539 i; 540 541 for (i = 0; i < entries; i++) { 542 entryOffset = dirStart + i * 12 + 2; 543 tag = strings[file.getUint16(entryOffset, !bigEnd)]; 544 if (!tag && debug) console.log("Unknown tag: " + file.getUint16(entryOffset, !bigEnd)); 545 tags[tag] = readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd); 546 } 547 return tags; 548 } 549 550 551 function readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd) { 552 var type = file.getUint16(entryOffset + 2, !bigEnd), 553 numValues = file.getUint32(entryOffset + 4, !bigEnd), 554 valueOffset = file.getUint32(entryOffset + 8, !bigEnd) + tiffStart, 555 offset, 556 vals, val, n, 557 numerator, denominator; 558 559 switch (type) { 560 case 1: // byte, 8-bit unsigned int 561 case 7: // undefined, 8-bit byte, value depending on field 562 if (numValues == 1) { 563 return file.getUint8(entryOffset + 8, !bigEnd); 564 } else { 565 offset = numValues > 4 ? valueOffset : (entryOffset + 8); 566 vals = []; 567 for (n = 0; n < numValues; n++) { 568 vals[n] = file.getUint8(offset + n); 569 } 570 return vals; 571 } 572 573 case 2: // ascii, 8-bit byte 574 offset = numValues > 4 ? valueOffset : (entryOffset + 8); 575 return getStringFromDB(file, offset, numValues - 1); 576 577 case 3: // short, 16 bit int 578 if (numValues == 1) { 579 return file.getUint16(entryOffset + 8, !bigEnd); 580 } else { 581 offset = numValues > 2 ? valueOffset : (entryOffset + 8); 582 vals = []; 583 for (n = 0; n < numValues; n++) { 584 vals[n] = file.getUint16(offset + 2 * n, !bigEnd); 585 } 586 return vals; 587 } 588 589 case 4: // long, 32 bit int 590 if (numValues == 1) { 591 return file.getUint32(entryOffset + 8, !bigEnd); 592 } else { 593 vals = []; 594 for (n = 0; n < numValues; n++) { 595 vals[n] = file.getUint32(valueOffset + 4 * n, !bigEnd); 596 } 597 return vals; 598 } 599 600 case 5: // rational = two long values, first is numerator, second is denominator 601 if (numValues == 1) { 602 numerator = file.getUint32(valueOffset, !bigEnd); 603 denominator = file.getUint32(valueOffset + 4, !bigEnd); 604 val = new Number(numerator / denominator); 605 val.numerator = numerator; 606 val.denominator = denominator; 607 return val; 608 } else { 609 vals = []; 610 for (n = 0; n < numValues; n++) { 611 numerator = file.getUint32(valueOffset + 8 * n, !bigEnd); 612 denominator = file.getUint32(valueOffset + 4 + 8 * n, !bigEnd); 613 vals[n] = new Number(numerator / denominator); 614 vals[n].numerator = numerator; 615 vals[n].denominator = denominator; 616 } 617 return vals; 618 } 619 620 case 9: // slong, 32 bit signed int 621 if (numValues == 1) { 622 return file.getInt32(entryOffset + 8, !bigEnd); 623 } else { 624 vals = []; 625 for (n = 0; n < numValues; n++) { 626 vals[n] = file.getInt32(valueOffset + 4 * n, !bigEnd); 627 } 628 return vals; 629 } 630 631 case 10: // signed rational, two slongs, first is numerator, second is denominator 632 if (numValues == 1) { 633 return file.getInt32(valueOffset, !bigEnd) / file.getInt32(valueOffset + 4, !bigEnd); 634 } else { 635 vals = []; 636 for (n = 0; n < numValues; n++) { 637 vals[n] = file.getInt32(valueOffset + 8 * n, !bigEnd) / file.getInt32(valueOffset + 4 + 8 * n, !bigEnd); 638 } 639 return vals; 640 } 641 } 642 } 643 644 function getStringFromDB(buffer, start, length) { 645 var outstr = ""; 646 for (n = start; n < start + length; n++) { 647 outstr += String.fromCharCode(buffer.getUint8(n)); 648 } 649 return outstr; 650 } 651 652 function readEXIFData(file, start) { 653 if (getStringFromDB(file, start, 4) != "Exif") { 654 if (debug) console.log("Not valid EXIF data! " + getStringFromDB(file, start, 4)); 655 return false; 656 } 657 658 var bigEnd, 659 tags, tag, 660 exifData, gpsData, 661 tiffOffset = start + 6; 662 663 // test for TIFF validity and endianness 664 if (file.getUint16(tiffOffset) == 0x4949) { 665 bigEnd = false; 666 } else if (file.getUint16(tiffOffset) == 0x4D4D) { 667 bigEnd = true; 668 } else { 669 if (debug) console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)"); 670 return false; 671 } 672 673 if (file.getUint16(tiffOffset + 2, !bigEnd) != 0x002A) { 674 if (debug) console.log("Not valid TIFF data! (no 0x002A)"); 675 return false; 676 } 677 678 var firstIFDOffset = file.getUint32(tiffOffset + 4, !bigEnd); 679 680 if (firstIFDOffset < 0x00000008) { 681 if (debug) console.log("Not valid TIFF data! (First offset less than 8)", file.getUint32(tiffOffset + 4, !bigEnd)); 682 return false; 683 } 684 685 tags = readTags(file, tiffOffset, tiffOffset + firstIFDOffset, TiffTags, bigEnd); 686 687 if (tags.ExifIFDPointer) { 688 exifData = readTags(file, tiffOffset, tiffOffset + tags.ExifIFDPointer, ExifTags, bigEnd); 689 for (tag in exifData) { 690 switch (tag) { 691 case "LightSource" : 692 case "Flash" : 693 case "MeteringMode" : 694 case "ExposureProgram" : 695 case "SensingMethod" : 696 case "SceneCaptureType" : 697 case "SceneType" : 698 case "CustomRendered" : 699 case "WhiteBalance" : 700 case "GainControl" : 701 case "Contrast" : 702 case "Saturation" : 703 case "Sharpness" : 704 case "SubjectDistanceRange" : 705 case "FileSource" : 706 exifData[tag] = StringValues[tag][exifData[tag]]; 707 break; 708 709 case "ExifVersion" : 710 case "FlashpixVersion" : 711 exifData[tag] = String.fromCharCode(exifData[tag][0], exifData[tag][1], exifData[tag][2], exifData[tag][3]); 712 break; 713 714 case "ComponentsConfiguration" : 715 exifData[tag] = 716 StringValues.Components[exifData[tag][0]] + 717 StringValues.Components[exifData[tag][1]] + 718 StringValues.Components[exifData[tag][2]] + 719 StringValues.Components[exifData[tag][3]]; 720 break; 721 } 722 tags[tag] = exifData[tag]; 723 } 724 } 725 726 if (tags.GPSInfoIFDPointer) { 727 gpsData = readTags(file, tiffOffset, tiffOffset + tags.GPSInfoIFDPointer, GPSTags, bigEnd); 728 for (tag in gpsData) { 729 switch (tag) { 730 case "GPSVersionID" : 731 gpsData[tag] = gpsData[tag][0] + 732 "." + gpsData[tag][1] + 733 "." + gpsData[tag][2] + 734 "." + gpsData[tag][3]; 735 break; 736 } 737 tags[tag] = gpsData[tag]; 738 } 739 } 740 741 return tags; 742 } 743 744 EXIF.getData = function (img, callback) { 745 if ((img instanceof Image || img instanceof HTMLImageElement) && !img.complete) return false; 746 747 if (!imageHasData(img)) { 748 getImageData(img, callback); 749 } else { 750 if (callback) { 751 callback.call(img); 752 } 753 } 754 return true; 755 } 756 757 EXIF.getTag = function (img, tag) { 758 if (!imageHasData(img)) return; 759 return img.exifdata[tag]; 760 } 761 762 EXIF.getAllTags = function (img) { 763 if (!imageHasData(img)) return {}; 764 var a, 765 data = img.exifdata, 766 tags = {}; 767 for (a in data) { 768 if (data.hasOwnProperty(a)) { 769 tags[a] = data[a]; 770 } 771 } 772 return tags; 773 } 774 775 EXIF.pretty = function (img) { 776 if (!imageHasData(img)) return ""; 777 var a, 778 data = img.exifdata, 779 strPretty = ""; 780 for (a in data) { 781 if (data.hasOwnProperty(a)) { 782 if (typeof data[a] == "object") { 783 if (data[a] instanceof Number) { 784 strPretty += a + " : " + data[a] + " [" + data[a].numerator + "/" + data[a].denominator + "]\r\n"; 785 } else { 786 strPretty += a + " : [" + data[a].length + " values]\r\n"; 787 } 788 } else { 789 strPretty += a + " : " + data[a] + "\r\n"; 790 } 791 } 792 } 793 return strPretty; 794 } 795 796 EXIF.readFromBinaryFile = function (file) { 797 return findEXIFinJPEG(file); 798 } 799 800 if (typeof define === 'function' && define.amd) { 801 define('exif-js', [], function () { 802 return EXIF; 803 }); 804 } 805}.call(this));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.