PageSourceSearch

https://www.ohkimslaw.com/_assets/vendor-cdn.imweb.me/js/jquery.exif__q_98f3ddb9.js

js ohkimslaw.com collected 2026-10-04 19:42:34 UTC 26,900 bytes, 958 lines download raw bytes

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

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.