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