25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

958 satır
37 KiB

  1. /*
  2. * Javascript EXIF Reader - jQuery plugin 0.1.3
  3. * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
  4. * Licensed under the MPL License [http://www.nihilogic.dk/licenses/mpl-license.txt]
  5. */
  6. /*
  7. * I added three functions for read EXIF from dataURL
  8. * - getImageDataFromDataURL
  9. * - getDataFromDataURL
  10. * - jQuery.fn.exifLoadFromDataURL
  11. *
  12. * http://orientation.gokercebeci.com
  13. * @gokercebeci
  14. */
  15. (function() {
  16. var BinaryFile = function(strData, iDataOffset, iDataLength) {
  17. var data = strData;
  18. var dataOffset = iDataOffset || 0;
  19. var dataLength = 0;
  20. this.getRawData = function() {
  21. return data;
  22. }
  23. if (typeof strData == "string") {
  24. dataLength = iDataLength || data.length;
  25. this.getByteAt = function(iOffset) {
  26. return data.charCodeAt(iOffset + dataOffset) & 0xFF;
  27. }
  28. } else if (typeof strData == "unknown") {
  29. dataLength = iDataLength || IEBinary_getLength(data);
  30. this.getByteAt = function(iOffset) {
  31. return IEBinary_getByteAt(data, iOffset + dataOffset);
  32. }
  33. }
  34. this.getLength = function() {
  35. return dataLength;
  36. }
  37. this.getSByteAt = function(iOffset) {
  38. var iByte = this.getByteAt(iOffset);
  39. if (iByte > 127)
  40. return iByte - 256;
  41. else
  42. return iByte;
  43. }
  44. this.getShortAt = function(iOffset, bBigEndian) {
  45. var iShort = bBigEndian ?
  46. (this.getByteAt(iOffset) << 8) + this.getByteAt(iOffset + 1)
  47. : (this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset)
  48. if (iShort < 0)
  49. iShort += 65536;
  50. return iShort;
  51. }
  52. this.getSShortAt = function(iOffset, bBigEndian) {
  53. var iUShort = this.getShortAt(iOffset, bBigEndian);
  54. if (iUShort > 32767)
  55. return iUShort - 65536;
  56. else
  57. return iUShort;
  58. }
  59. this.getLongAt = function(iOffset, bBigEndian) {
  60. var iByte1 = this.getByteAt(iOffset),
  61. iByte2 = this.getByteAt(iOffset + 1),
  62. iByte3 = this.getByteAt(iOffset + 2),
  63. iByte4 = this.getByteAt(iOffset + 3);
  64. var iLong = bBigEndian ?
  65. (((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4
  66. : (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1;
  67. if (iLong < 0)
  68. iLong += 4294967296;
  69. return iLong;
  70. }
  71. this.getSLongAt = function(iOffset, bBigEndian) {
  72. var iULong = this.getLongAt(iOffset, bBigEndian);
  73. if (iULong > 2147483647)
  74. return iULong - 4294967296;
  75. else
  76. return iULong;
  77. }
  78. this.getStringAt = function(iOffset, iLength) {
  79. var aStr = [];
  80. for (var i = iOffset, j = 0; i < iOffset + iLength; i++, j++) {
  81. aStr[j] = String.fromCharCode(this.getByteAt(i));
  82. }
  83. return aStr.join("");
  84. }
  85. this.getCharAt = function(iOffset) {
  86. return String.fromCharCode(this.getByteAt(iOffset));
  87. }
  88. this.toBase64 = function() {
  89. return window.btoa(data);
  90. }
  91. this.fromBase64 = function(strBase64) {
  92. data = window.atob(strBase64);
  93. }
  94. }
  95. var BinaryAjax = (function() {
  96. function createRequest() {
  97. var oHTTP = null;
  98. if (window.XMLHttpRequest) {
  99. oHTTP = new XMLHttpRequest();
  100. } else if (window.ActiveXObject) {
  101. oHTTP = new ActiveXObject("Microsoft.XMLHTTP");
  102. }
  103. return oHTTP;
  104. }
  105. function getHead(strURL, fncCallback, fncError) {
  106. var oHTTP = createRequest();
  107. if (oHTTP) {
  108. if (fncCallback) {
  109. if (typeof(oHTTP.onload) != "undefined") {
  110. oHTTP.onload = function() {
  111. if (oHTTP.status == "200") {
  112. fncCallback(this);
  113. } else {
  114. if (fncError)
  115. fncError();
  116. }
  117. oHTTP = null;
  118. };
  119. } else {
  120. oHTTP.onreadystatechange = function() {
  121. if (oHTTP.readyState == 4) {
  122. if (oHTTP.status == "200") {
  123. fncCallback(this);
  124. } else {
  125. if (fncError)
  126. fncError();
  127. }
  128. oHTTP = null;
  129. }
  130. };
  131. }
  132. }
  133. oHTTP.open("HEAD", strURL, true);
  134. oHTTP.send(null);
  135. } else {
  136. if (fncError)
  137. fncError();
  138. }
  139. }
  140. function sendRequest(strURL, fncCallback, fncError, aRange, bAcceptRanges, iFileSize) {
  141. var oHTTP = createRequest();
  142. if (oHTTP) {
  143. var iDataOffset = 0;
  144. if (aRange && !bAcceptRanges) {
  145. iDataOffset = aRange[0];
  146. }
  147. var iDataLen = 0;
  148. if (aRange) {
  149. iDataLen = aRange[1] - aRange[0] + 1;
  150. }
  151. if (fncCallback) {
  152. if (typeof(oHTTP.onload) != "undefined") {
  153. oHTTP.onload = function() {
  154. if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") {
  155. this.binaryResponse = new BinaryFile(this.responseText, iDataOffset, iDataLen);
  156. this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
  157. fncCallback(this);
  158. } else {
  159. if (fncError)
  160. fncError();
  161. }
  162. oHTTP = null;
  163. };
  164. } else {
  165. oHTTP.onreadystatechange = function() {
  166. if (oHTTP.readyState == 4) {
  167. if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") {
  168. this.binaryResponse = new BinaryFile(oHTTP.responseBody, iDataOffset, iDataLen);
  169. this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
  170. fncCallback(this);
  171. } else {
  172. if (fncError)
  173. fncError();
  174. }
  175. oHTTP = null;
  176. }
  177. };
  178. }
  179. }
  180. oHTTP.open("GET", strURL, true);
  181. if (oHTTP.overrideMimeType)
  182. oHTTP.overrideMimeType('text/plain; charset=x-user-defined');
  183. if (aRange && bAcceptRanges) {
  184. oHTTP.setRequestHeader("Range", "bytes=" + aRange[0] + "-" + aRange[1]);
  185. }
  186. oHTTP.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT");
  187. oHTTP.send(null);
  188. } else {
  189. if (fncError)
  190. fncError();
  191. }
  192. }
  193. return function(strURL, fncCallback, fncError, aRange) {
  194. if (aRange) {
  195. getHead(
  196. strURL,
  197. function(oHTTP) {
  198. var iLength = parseInt(oHTTP.getResponseHeader("Content-Length"), 10);
  199. var strAcceptRanges = oHTTP.getResponseHeader("Accept-Ranges");
  200. var iStart, iEnd;
  201. iStart = aRange[0];
  202. if (aRange[0] < 0)
  203. iStart += iLength;
  204. iEnd = iStart + aRange[1] - 1;
  205. sendRequest(strURL, fncCallback, fncError, [iStart, iEnd], (strAcceptRanges == "bytes"), iLength);
  206. }
  207. );
  208. } else {
  209. sendRequest(strURL, fncCallback, fncError);
  210. }
  211. }
  212. }());
  213. var script = document.createElement("script");
  214. script.type = 'text/vbscript';
  215. script.innerHTML =
  216. "Function IEBinary_getByteAt(strBinary, iOffset)\r\n"
  217. + " IEBinary_getByteAt = AscB(MidB(strBinary,iOffset+1,1))\r\n"
  218. + "End Function\r\n"
  219. + "Function IEBinary_getLength(strBinary)\r\n"
  220. + " IEBinary_getLength = LenB(strBinary)\r\n"
  221. + "End Function";
  222. document.head.appendChild(script);
  223. var EXIF = {};
  224. (function() {
  225. var bDebug = false;
  226. EXIF.Tags = {
  227. // version tags
  228. 0x9000: "ExifVersion", // EXIF version
  229. 0xA000: "FlashpixVersion", // Flashpix format version
  230. // colorspace tags
  231. 0xA001: "ColorSpace", // Color space information tag
  232. // image configuration
  233. 0xA002: "PixelXDimension", // Valid width of meaningful image
  234. 0xA003: "PixelYDimension", // Valid height of meaningful image
  235. 0x9101: "ComponentsConfiguration", // Information about channels
  236. 0x9102: "CompressedBitsPerPixel", // Compressed bits per pixel
  237. // user information
  238. 0x927C: "MakerNote", // Any desired information written by the manufacturer
  239. 0x9286: "UserComment", // Comments by user
  240. // related file
  241. 0xA004: "RelatedSoundFile", // Name of related sound file
  242. // date and time
  243. 0x9003: "DateTimeOriginal", // Date and time when the original image was generated
  244. 0x9004: "DateTimeDigitized", // Date and time when the image was stored digitally
  245. 0x9290: "SubsecTime", // Fractions of seconds for DateTime
  246. 0x9291: "SubsecTimeOriginal", // Fractions of seconds for DateTimeOriginal
  247. 0x9292: "SubsecTimeDigitized", // Fractions of seconds for DateTimeDigitized
  248. // picture-taking conditions
  249. 0x829A: "ExposureTime", // Exposure time (in seconds)
  250. 0x829D: "FNumber", // F number
  251. 0x8822: "ExposureProgram", // Exposure program
  252. 0x8824: "SpectralSensitivity", // Spectral sensitivity
  253. 0x8827: "ISOSpeedRatings", // ISO speed rating
  254. 0x8828: "OECF", // Optoelectric conversion factor
  255. 0x9201: "ShutterSpeedValue", // Shutter speed
  256. 0x9202: "ApertureValue", // Lens aperture
  257. 0x9203: "BrightnessValue", // Value of brightness
  258. 0x9204: "ExposureBias", // Exposure bias
  259. 0x9205: "MaxApertureValue", // Smallest F number of lens
  260. 0x9206: "SubjectDistance", // Distance to subject in meters
  261. 0x9207: "MeteringMode", // Metering mode
  262. 0x9208: "LightSource", // Kind of light source
  263. 0x9209: "Flash", // Flash status
  264. 0x9214: "SubjectArea", // Location and area of main subject
  265. 0x920A: "FocalLength", // Focal length of the lens in mm
  266. 0xA20B: "FlashEnergy", // Strobe energy in BCPS
  267. 0xA20C: "SpatialFrequencyResponse", //
  268. 0xA20E: "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit
  269. 0xA20F: "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit
  270. 0xA210: "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution
  271. 0xA214: "SubjectLocation", // Location of subject in image
  272. 0xA215: "ExposureIndex", // Exposure index selected on camera
  273. 0xA217: "SensingMethod", // Image sensor type
  274. 0xA300: "FileSource", // Image source (3 == DSC)
  275. 0xA301: "SceneType", // Scene type (1 == directly photographed)
  276. 0xA302: "CFAPattern", // Color filter array geometric pattern
  277. 0xA401: "CustomRendered", // Special processing
  278. 0xA402: "ExposureMode", // Exposure mode
  279. 0xA403: "WhiteBalance", // 1 = auto white balance, 2 = manual
  280. 0xA404: "DigitalZoomRation", // Digital zoom ratio
  281. 0xA405: "FocalLengthIn35mmFilm", // Equivalent foacl length assuming 35mm film camera (in mm)
  282. 0xA406: "SceneCaptureType", // Type of scene
  283. 0xA407: "GainControl", // Degree of overall image gain adjustment
  284. 0xA408: "Contrast", // Direction of contrast processing applied by camera
  285. 0xA409: "Saturation", // Direction of saturation processing applied by camera
  286. 0xA40A: "Sharpness", // Direction of sharpness processing applied by camera
  287. 0xA40B: "DeviceSettingDescription", //
  288. 0xA40C: "SubjectDistanceRange", // Distance to subject
  289. // other tags
  290. 0xA005: "InteroperabilityIFDPointer",
  291. 0xA420: "ImageUniqueID" // Identifier assigned uniquely to each image
  292. };
  293. EXIF.TiffTags = {
  294. 0x0100: "ImageWidth",
  295. 0x0101: "ImageHeight",
  296. 0x8769: "ExifIFDPointer",
  297. 0x8825: "GPSInfoIFDPointer",
  298. 0xA005: "InteroperabilityIFDPointer",
  299. 0x0102: "BitsPerSample",
  300. 0x0103: "Compression",
  301. 0x0106: "PhotometricInterpretation",
  302. 0x0112: "Orientation",
  303. 0x0115: "SamplesPerPixel",
  304. 0x011C: "PlanarConfiguration",
  305. 0x0212: "YCbCrSubSampling",
  306. 0x0213: "YCbCrPositioning",
  307. 0x011A: "XResolution",
  308. 0x011B: "YResolution",
  309. 0x0128: "ResolutionUnit",
  310. 0x0111: "StripOffsets",
  311. 0x0116: "RowsPerStrip",
  312. 0x0117: "StripByteCounts",
  313. 0x0201: "JPEGInterchangeFormat",
  314. 0x0202: "JPEGInterchangeFormatLength",
  315. 0x012D: "TransferFunction",
  316. 0x013E: "WhitePoint",
  317. 0x013F: "PrimaryChromaticities",
  318. 0x0211: "YCbCrCoefficients",
  319. 0x0214: "ReferenceBlackWhite",
  320. 0x0132: "DateTime",
  321. 0x010E: "ImageDescription",
  322. 0x010F: "Make",
  323. 0x0110: "Model",
  324. 0x0131: "Software",
  325. 0x013B: "Artist",
  326. 0x8298: "Copyright"
  327. }
  328. EXIF.GPSTags = {
  329. 0x0000: "GPSVersionID",
  330. 0x0001: "GPSLatitudeRef",
  331. 0x0002: "GPSLatitude",
  332. 0x0003: "GPSLongitudeRef",
  333. 0x0004: "GPSLongitude",
  334. 0x0005: "GPSAltitudeRef",
  335. 0x0006: "GPSAltitude",
  336. 0x0007: "GPSTimeStamp",
  337. 0x0008: "GPSSatellites",
  338. 0x0009: "GPSStatus",
  339. 0x000A: "GPSMeasureMode",
  340. 0x000B: "GPSDOP",
  341. 0x000C: "GPSSpeedRef",
  342. 0x000D: "GPSSpeed",
  343. 0x000E: "GPSTrackRef",
  344. 0x000F: "GPSTrack",
  345. 0x0010: "GPSImgDirectionRef",
  346. 0x0011: "GPSImgDirection",
  347. 0x0012: "GPSMapDatum",
  348. 0x0013: "GPSDestLatitudeRef",
  349. 0x0014: "GPSDestLatitude",
  350. 0x0015: "GPSDestLongitudeRef",
  351. 0x0016: "GPSDestLongitude",
  352. 0x0017: "GPSDestBearingRef",
  353. 0x0018: "GPSDestBearing",
  354. 0x0019: "GPSDestDistanceRef",
  355. 0x001A: "GPSDestDistance",
  356. 0x001B: "GPSProcessingMethod",
  357. 0x001C: "GPSAreaInformation",
  358. 0x001D: "GPSDateStamp",
  359. 0x001E: "GPSDifferential"
  360. }
  361. EXIF.StringValues = {
  362. ExposureProgram: {
  363. 0: "Not defined",
  364. 1: "Manual",
  365. 2: "Normal program",
  366. 3: "Aperture priority",
  367. 4: "Shutter priority",
  368. 5: "Creative program",
  369. 6: "Action program",
  370. 7: "Portrait mode",
  371. 8: "Landscape mode"
  372. },
  373. MeteringMode: {
  374. 0: "Unknown",
  375. 1: "Average",
  376. 2: "CenterWeightedAverage",
  377. 3: "Spot",
  378. 4: "MultiSpot",
  379. 5: "Pattern",
  380. 6: "Partial",
  381. 255: "Other"
  382. },
  383. LightSource: {
  384. 0: "Unknown",
  385. 1: "Daylight",
  386. 2: "Fluorescent",
  387. 3: "Tungsten (incandescent light)",
  388. 4: "Flash",
  389. 9: "Fine weather",
  390. 10: "Cloudy weather",
  391. 11: "Shade",
  392. 12: "Daylight fluorescent (D 5700 - 7100K)",
  393. 13: "Day white fluorescent (N 4600 - 5400K)",
  394. 14: "Cool white fluorescent (W 3900 - 4500K)",
  395. 15: "White fluorescent (WW 3200 - 3700K)",
  396. 17: "Standard light A",
  397. 18: "Standard light B",
  398. 19: "Standard light C",
  399. 20: "D55",
  400. 21: "D65",
  401. 22: "D75",
  402. 23: "D50",
  403. 24: "ISO studio tungsten",
  404. 255: "Other"
  405. },
  406. Flash: {
  407. 0x0000: "Flash did not fire",
  408. 0x0001: "Flash fired",
  409. 0x0005: "Strobe return light not detected",
  410. 0x0007: "Strobe return light detected",
  411. 0x0009: "Flash fired, compulsory flash mode",
  412. 0x000D: "Flash fired, compulsory flash mode, return light not detected",
  413. 0x000F: "Flash fired, compulsory flash mode, return light detected",
  414. 0x0010: "Flash did not fire, compulsory flash mode",
  415. 0x0018: "Flash did not fire, auto mode",
  416. 0x0019: "Flash fired, auto mode",
  417. 0x001D: "Flash fired, auto mode, return light not detected",
  418. 0x001F: "Flash fired, auto mode, return light detected",
  419. 0x0020: "No flash function",
  420. 0x0041: "Flash fired, red-eye reduction mode",
  421. 0x0045: "Flash fired, red-eye reduction mode, return light not detected",
  422. 0x0047: "Flash fired, red-eye reduction mode, return light detected",
  423. 0x0049: "Flash fired, compulsory flash mode, red-eye reduction mode",
  424. 0x004D: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",
  425. 0x004F: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",
  426. 0x0059: "Flash fired, auto mode, red-eye reduction mode",
  427. 0x005D: "Flash fired, auto mode, return light not detected, red-eye reduction mode",
  428. 0x005F: "Flash fired, auto mode, return light detected, red-eye reduction mode"
  429. },
  430. SensingMethod: {
  431. 1: "Not defined",
  432. 2: "One-chip color area sensor",
  433. 3: "Two-chip color area sensor",
  434. 4: "Three-chip color area sensor",
  435. 5: "Color sequential area sensor",
  436. 7: "Trilinear sensor",
  437. 8: "Color sequential linear sensor"
  438. },
  439. SceneCaptureType: {
  440. 0: "Standard",
  441. 1: "Landscape",
  442. 2: "Portrait",
  443. 3: "Night scene"
  444. },
  445. SceneType: {
  446. 1: "Directly photographed"
  447. },
  448. CustomRendered: {
  449. 0: "Normal process",
  450. 1: "Custom process"
  451. },
  452. WhiteBalance: {
  453. 0: "Auto white balance",
  454. 1: "Manual white balance"
  455. },
  456. GainControl: {
  457. 0: "None",
  458. 1: "Low gain up",
  459. 2: "High gain up",
  460. 3: "Low gain down",
  461. 4: "High gain down"
  462. },
  463. Contrast: {
  464. 0: "Normal",
  465. 1: "Soft",
  466. 2: "Hard"
  467. },
  468. Saturation: {
  469. 0: "Normal",
  470. 1: "Low saturation",
  471. 2: "High saturation"
  472. },
  473. Sharpness: {
  474. 0: "Normal",
  475. 1: "Soft",
  476. 2: "Hard"
  477. },
  478. SubjectDistanceRange: {
  479. 0: "Unknown",
  480. 1: "Macro",
  481. 2: "Close view",
  482. 3: "Distant view"
  483. },
  484. FileSource: {
  485. 3: "DSC"
  486. },
  487. Components: {
  488. 0: "",
  489. 1: "Y",
  490. 2: "Cb",
  491. 3: "Cr",
  492. 4: "R",
  493. 5: "G",
  494. 6: "B"
  495. }
  496. }
  497. function addEvent(oElement, strEvent, fncHandler)
  498. {
  499. if (oElement.addEventListener) {
  500. oElement.addEventListener(strEvent, fncHandler, false);
  501. } else if (oElement.attachEvent) {
  502. oElement.attachEvent("on" + strEvent, fncHandler);
  503. }
  504. }
  505. function imageHasData(oImg)
  506. {
  507. return !!(oImg.exifdata);
  508. }
  509. function getImageData(oImg, fncCallback)
  510. {
  511. BinaryAjax(
  512. oImg.src,
  513. function(oHTTP) {
  514. console.log('BINARY', oHTTP.binaryResponse);
  515. var oEXIF = findEXIFinJPEG(oHTTP.binaryResponse);
  516. oImg.exifdata = oEXIF || {};
  517. if (fncCallback)
  518. fncCallback();
  519. }
  520. )
  521. }
  522. function getImageDataFromDataURL(oImg, fncCallback)
  523. {
  524. var byteString = atob(oImg.src.split(',')[1]);
  525. var f = new BinaryFile(byteString, 0, byteString.length)
  526. var oEXIF = findEXIFinJPEG(f);
  527. oImg.exifdata = oEXIF || {};
  528. if (fncCallback)
  529. fncCallback();
  530. }
  531. function findEXIFinJPEG(oFile) {
  532. var aMarkers = [];
  533. if (oFile.getByteAt(0) != 0xFF || oFile.getByteAt(1) != 0xD8) {
  534. return false; // not a valid jpeg
  535. }
  536. var iOffset = 2;
  537. var iLength = oFile.getLength();
  538. while (iOffset < iLength) {
  539. if (oFile.getByteAt(iOffset) != 0xFF) {
  540. if (bDebug)
  541. console.log("Not a valid marker at offset " + iOffset + ", found: " + oFile.getByteAt(iOffset));
  542. return false; // not a valid marker, something is wrong
  543. }
  544. var iMarker = oFile.getByteAt(iOffset + 1);
  545. // we could implement handling for other markers here,
  546. // but we're only looking for 0xFFE1 for EXIF data
  547. if (iMarker == 22400) {
  548. if (bDebug)
  549. console.log("Found 0xFFE1 marker");
  550. return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset + 2, true) - 2);
  551. iOffset += 2 + oFile.getShortAt(iOffset + 2, true);
  552. } else if (iMarker == 225) {
  553. // 0xE1 = Application-specific 1 (for EXIF)
  554. if (bDebug)
  555. console.log("Found 0xFFE1 marker");
  556. return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset + 2, true) - 2);
  557. } else {
  558. iOffset += 2 + oFile.getShortAt(iOffset + 2, true);
  559. }
  560. }
  561. }
  562. function readTags(oFile, iTIFFStart, iDirStart, oStrings, bBigEnd)
  563. {
  564. var iEntries = oFile.getShortAt(iDirStart, bBigEnd);
  565. var oTags = {};
  566. for (var i = 0; i < iEntries; i++) {
  567. var iEntryOffset = iDirStart + i * 12 + 2;
  568. var strTag = oStrings[oFile.getShortAt(iEntryOffset, bBigEnd)];
  569. if (!strTag && bDebug)
  570. console.log("Unknown tag: " + oFile.getShortAt(iEntryOffset, bBigEnd));
  571. oTags[strTag] = readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd);
  572. }
  573. return oTags;
  574. }
  575. function readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd)
  576. {
  577. var iType = oFile.getShortAt(iEntryOffset + 2, bBigEnd);
  578. var iNumValues = oFile.getLongAt(iEntryOffset + 4, bBigEnd);
  579. var iValueOffset = oFile.getLongAt(iEntryOffset + 8, bBigEnd) + iTIFFStart;
  580. switch (iType) {
  581. case 1: // byte, 8-bit unsigned int
  582. case 7: // undefined, 8-bit byte, value depending on field
  583. if (iNumValues == 1) {
  584. return oFile.getByteAt(iEntryOffset + 8, bBigEnd);
  585. } else {
  586. var iValOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
  587. var aVals = [];
  588. for (var n = 0; n < iNumValues; n++) {
  589. aVals[n] = oFile.getByteAt(iValOffset + n);
  590. }
  591. return aVals;
  592. }
  593. break;
  594. case 2: // ascii, 8-bit byte
  595. var iStringOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
  596. return oFile.getStringAt(iStringOffset, iNumValues - 1);
  597. break;
  598. case 3: // short, 16 bit int
  599. if (iNumValues == 1) {
  600. return oFile.getShortAt(iEntryOffset + 8, bBigEnd);
  601. } else {
  602. var iValOffset = iNumValues > 2 ? iValueOffset : (iEntryOffset + 8);
  603. var aVals = [];
  604. for (var n = 0; n < iNumValues; n++) {
  605. aVals[n] = oFile.getShortAt(iValOffset + 2 * n, bBigEnd);
  606. }
  607. return aVals;
  608. }
  609. break;
  610. case 4: // long, 32 bit int
  611. if (iNumValues == 1) {
  612. return oFile.getLongAt(iEntryOffset + 8, bBigEnd);
  613. } else {
  614. var aVals = [];
  615. for (var n = 0; n < iNumValues; n++) {
  616. aVals[n] = oFile.getLongAt(iValueOffset + 4 * n, bBigEnd);
  617. }
  618. return aVals;
  619. }
  620. break;
  621. case 5: // rational = two long values, first is numerator, second is denominator
  622. if (iNumValues == 1) {
  623. return oFile.getLongAt(iValueOffset, bBigEnd) / oFile.getLongAt(iValueOffset + 4, bBigEnd);
  624. } else {
  625. var aVals = [];
  626. for (var n = 0; n < iNumValues; n++) {
  627. aVals[n] = oFile.getLongAt(iValueOffset + 8 * n, bBigEnd) / oFile.getLongAt(iValueOffset + 4 + 8 * n, bBigEnd);
  628. }
  629. return aVals;
  630. }
  631. break;
  632. case 9: // slong, 32 bit signed int
  633. if (iNumValues == 1) {
  634. return oFile.getSLongAt(iEntryOffset + 8, bBigEnd);
  635. } else {
  636. var aVals = [];
  637. for (var n = 0; n < iNumValues; n++) {
  638. aVals[n] = oFile.getSLongAt(iValueOffset + 4 * n, bBigEnd);
  639. }
  640. return aVals;
  641. }
  642. break;
  643. case 10: // signed rational, two slongs, first is numerator, second is denominator
  644. if (iNumValues == 1) {
  645. return oFile.getSLongAt(iValueOffset, bBigEnd) / oFile.getSLongAt(iValueOffset + 4, bBigEnd);
  646. } else {
  647. var aVals = [];
  648. for (var n = 0; n < iNumValues; n++) {
  649. aVals[n] = oFile.getSLongAt(iValueOffset + 8 * n, bBigEnd) / oFile.getSLongAt(iValueOffset + 4 + 8 * n, bBigEnd);
  650. }
  651. return aVals;
  652. }
  653. break;
  654. }
  655. }
  656. function readEXIFData(oFile, iStart, iLength)
  657. {
  658. if (oFile.getStringAt(iStart, 4) != "Exif") {
  659. if (bDebug)
  660. console.log("Not valid EXIF data! " + oFile.getStringAt(iStart, 4));
  661. return false;
  662. }
  663. var bBigEnd;
  664. var iTIFFOffset = iStart + 6;
  665. // test for TIFF validity and endianness
  666. if (oFile.getShortAt(iTIFFOffset) == 0x4949) {
  667. bBigEnd = false;
  668. } else if (oFile.getShortAt(iTIFFOffset) == 0x4D4D) {
  669. bBigEnd = true;
  670. } else {
  671. if (bDebug)
  672. console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");
  673. return false;
  674. }
  675. if (oFile.getShortAt(iTIFFOffset + 2, bBigEnd) != 0x002A) {
  676. if (bDebug)
  677. console.log("Not valid TIFF data! (no 0x002A)");
  678. return false;
  679. }
  680. if (oFile.getLongAt(iTIFFOffset + 4, bBigEnd) != 0x00000008) {
  681. if (bDebug)
  682. console.log("Not valid TIFF data! (First offset not 8)", oFile.getShortAt(iTIFFOffset + 4, bBigEnd));
  683. return false;
  684. }
  685. var oTags = readTags(oFile, iTIFFOffset, iTIFFOffset + 8, EXIF.TiffTags, bBigEnd);
  686. if (oTags.ExifIFDPointer) {
  687. var oEXIFTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.ExifIFDPointer, EXIF.Tags, bBigEnd);
  688. for (var strTag in oEXIFTags) {
  689. switch (strTag) {
  690. case "LightSource" :
  691. case "Flash" :
  692. case "MeteringMode" :
  693. case "ExposureProgram" :
  694. case "SensingMethod" :
  695. case "SceneCaptureType" :
  696. case "SceneType" :
  697. case "CustomRendered" :
  698. case "WhiteBalance" :
  699. case "GainControl" :
  700. case "Contrast" :
  701. case "Saturation" :
  702. case "Sharpness" :
  703. case "SubjectDistanceRange" :
  704. case "FileSource" :
  705. oEXIFTags[strTag] = EXIF.StringValues[strTag][oEXIFTags[strTag]];
  706. break;
  707. case "ExifVersion" :
  708. case "FlashpixVersion" :
  709. oEXIFTags[strTag] = String.fromCharCode(oEXIFTags[strTag][0], oEXIFTags[strTag][1], oEXIFTags[strTag][2], oEXIFTags[strTag][3]);
  710. break;
  711. case "ComponentsConfiguration" :
  712. oEXIFTags[strTag] =
  713. EXIF.StringValues.Components[oEXIFTags[strTag][0]]
  714. + EXIF.StringValues.Components[oEXIFTags[strTag][1]]
  715. + EXIF.StringValues.Components[oEXIFTags[strTag][2]]
  716. + EXIF.StringValues.Components[oEXIFTags[strTag][3]];
  717. break;
  718. }
  719. oTags[strTag] = oEXIFTags[strTag];
  720. }
  721. }
  722. if (oTags.GPSInfoIFDPointer) {
  723. var oGPSTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.GPSInfoIFDPointer, EXIF.GPSTags, bBigEnd);
  724. for (var strTag in oGPSTags) {
  725. switch (strTag) {
  726. case "GPSVersionID" :
  727. oGPSTags[strTag] = oGPSTags[strTag][0]
  728. + "." + oGPSTags[strTag][1]
  729. + "." + oGPSTags[strTag][2]
  730. + "." + oGPSTags[strTag][3];
  731. break;
  732. }
  733. oTags[strTag] = oGPSTags[strTag];
  734. }
  735. }
  736. return oTags;
  737. }
  738. EXIF.getData = function(oImg, fncCallback)
  739. {
  740. if (!oImg.complete)
  741. return false;
  742. if (!imageHasData(oImg)) {
  743. getImageData(oImg, fncCallback);
  744. } else {
  745. if (fncCallback)
  746. fncCallback();
  747. }
  748. return true;
  749. }
  750. EXIF.getDataFromDataURL = function(oImg, fncCallback)
  751. {
  752. if (!oImg.complete)
  753. return false;
  754. if (!imageHasData(oImg)) {
  755. getImageDataFromDataURL(oImg, fncCallback);
  756. } else {
  757. if (fncCallback)
  758. fncCallback();
  759. }
  760. return true;
  761. }
  762. EXIF.getTag = function(oImg, strTag)
  763. {
  764. if (!imageHasData(oImg))
  765. return;
  766. return oImg.exifdata[strTag];
  767. }
  768. EXIF.getAllTags = function(oImg)
  769. {
  770. if (!imageHasData(oImg))
  771. return {};
  772. var oData = oImg.exifdata;
  773. var oAllTags = {};
  774. for (var a in oData) {
  775. if (oData.hasOwnProperty(a)) {
  776. oAllTags[a] = oData[a];
  777. }
  778. }
  779. return oAllTags;
  780. }
  781. EXIF.pretty = function(oImg)
  782. {
  783. if (!imageHasData(oImg))
  784. return "";
  785. var oData = oImg.exifdata;
  786. var strPretty = "";
  787. for (var a in oData) {
  788. if (oData.hasOwnProperty(a)) {
  789. if (typeof oData[a] == "object") {
  790. strPretty += a + " : [" + oData[a].length + " values]\r\n";
  791. } else {
  792. strPretty += a + " : " + oData[a] + "\r\n";
  793. }
  794. }
  795. }
  796. return strPretty;
  797. }
  798. EXIF.readFromBinaryFile = function(oFile) {
  799. return findEXIFinJPEG(oFile);
  800. }
  801. function loadAllImages()
  802. {
  803. var aImages = document.getElementsByTagName("img");
  804. for (var i = 0; i < aImages.length; i++) {
  805. if (aImages[i].getAttribute("exif") == "true") {
  806. if (!aImages[i].complete) {
  807. addEvent(aImages[i], "load",
  808. function() {
  809. EXIF.getData(this);
  810. }
  811. );
  812. } else {
  813. EXIF.getData(aImages[i]);
  814. }
  815. }
  816. }
  817. }
  818. // automatically load exif data for all images with exif=true when doc is ready
  819. jQuery(document).ready(loadAllImages);
  820. // load data for images manually
  821. jQuery.fn.exifLoad = function(fncCallback) {
  822. return this.each(function() {
  823. EXIF.getData(this, fncCallback)
  824. });
  825. }
  826. // load data for images manually
  827. jQuery.fn.exifLoadFromDataURL = function(fncCallback) {
  828. return this.each(function() {
  829. EXIF.getDataFromDataURL(this, fncCallback)
  830. return true;
  831. });
  832. }
  833. jQuery.fn.exif = function(strTag) {
  834. var aStrings = [];
  835. this.each(function() {
  836. aStrings.push(EXIF.getTag(this, strTag));
  837. });
  838. return aStrings;
  839. }
  840. jQuery.fn.exifAll = function() {
  841. var aStrings = [];
  842. this.each(function() {
  843. aStrings.push(EXIF.getAllTags(this));
  844. });
  845. return aStrings;
  846. }
  847. jQuery.fn.exifPretty = function() {
  848. var aStrings = [];
  849. this.each(function() {
  850. aStrings.push(EXIF.pretty(this));
  851. });
  852. return aStrings;
  853. }
  854. })();
  855. })();