mirror of
				https://github.com/flynx/PortableMag.git
				synced 2025-10-31 03:50:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			895 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			895 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| 
 | |
| /*
 | |
|  * Javascript EXIF Reader - jQuery plugin 0.1.3
 | |
|  * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
 | |
|  * Licensed under the MPL License [http://www.nihilogic.dk/licenses/mpl-license.txt]
 | |
|  */
 | |
| 
 | |
| (function() {
 | |
| 
 | |
| 
 | |
| var BinaryFile = function(strData, iDataOffset, iDataLength) {
 | |
| 	var data = strData;
 | |
| 	var dataOffset = iDataOffset || 0;
 | |
| 	var dataLength = 0;
 | |
| 
 | |
| 	this.getRawData = function() {
 | |
| 		return data;
 | |
| 	}
 | |
| 
 | |
| 	if (typeof strData == "string") {
 | |
| 		dataLength = iDataLength || data.length;
 | |
| 
 | |
| 		this.getByteAt = function(iOffset) {
 | |
| 			return data.charCodeAt(iOffset + dataOffset) & 0xFF;
 | |
| 		}
 | |
| 	} else if (typeof strData == "unknown") {
 | |
| 		dataLength = iDataLength || IEBinary_getLength(data);
 | |
| 
 | |
| 		this.getByteAt = function(iOffset) {
 | |
| 			return IEBinary_getByteAt(data, iOffset + dataOffset);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	this.getLength = function() {
 | |
| 		return dataLength;
 | |
| 	}
 | |
| 
 | |
| 	this.getSByteAt = function(iOffset) {
 | |
| 		var iByte = this.getByteAt(iOffset);
 | |
| 		if (iByte > 127)
 | |
| 			return iByte - 256;
 | |
| 		else
 | |
| 			return iByte;
 | |
| 	}
 | |
| 
 | |
| 	this.getShortAt = function(iOffset, bBigEndian) {
 | |
| 		var iShort = bBigEndian ? 
 | |
| 			(this.getByteAt(iOffset) << 8) + this.getByteAt(iOffset + 1)
 | |
| 			: (this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset)
 | |
| 		if (iShort < 0) iShort += 65536;
 | |
| 		return iShort;
 | |
| 	}
 | |
| 	this.getSShortAt = function(iOffset, bBigEndian) {
 | |
| 		var iUShort = this.getShortAt(iOffset, bBigEndian);
 | |
| 		if (iUShort > 32767)
 | |
| 			return iUShort - 65536;
 | |
| 		else
 | |
| 			return iUShort;
 | |
| 	}
 | |
| 	this.getLongAt = function(iOffset, bBigEndian) {
 | |
| 		var iByte1 = this.getByteAt(iOffset),
 | |
| 			iByte2 = this.getByteAt(iOffset + 1),
 | |
| 			iByte3 = this.getByteAt(iOffset + 2),
 | |
| 			iByte4 = this.getByteAt(iOffset + 3);
 | |
| 
 | |
| 		var iLong = bBigEndian ? 
 | |
| 			(((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4
 | |
| 			: (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1;
 | |
| 		if (iLong < 0) iLong += 4294967296;
 | |
| 		return iLong;
 | |
| 	}
 | |
| 	this.getSLongAt = function(iOffset, bBigEndian) {
 | |
| 		var iULong = this.getLongAt(iOffset, bBigEndian);
 | |
| 		if (iULong > 2147483647)
 | |
| 			return iULong - 4294967296;
 | |
| 		else
 | |
| 			return iULong;
 | |
| 	}
 | |
| 	this.getStringAt = function(iOffset, iLength) {
 | |
| 		var aStr = [];
 | |
| 		for (var i=iOffset,j=0;i<iOffset+iLength;i++,j++) {
 | |
| 			aStr[j] = String.fromCharCode(this.getByteAt(i));
 | |
| 		}
 | |
| 		return aStr.join("");
 | |
| 	}
 | |
| 
 | |
| 	this.getCharAt = function(iOffset) {
 | |
| 		return String.fromCharCode(this.getByteAt(iOffset));
 | |
| 	}
 | |
| 	this.toBase64 = function() {
 | |
| 		return window.btoa(data);
 | |
| 	}
 | |
| 	this.fromBase64 = function(strBase64) {
 | |
| 		data = window.atob(strBase64);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| var BinaryAjax = (function() {
 | |
| 
 | |
| 	function createRequest() {
 | |
| 		var oHTTP = null;
 | |
| 		if (window.XMLHttpRequest) {
 | |
| 			oHTTP = new XMLHttpRequest();
 | |
| 		} else if (window.ActiveXObject) {
 | |
| 			oHTTP = new ActiveXObject("Microsoft.XMLHTTP");
 | |
| 		}
 | |
| 		return oHTTP;
 | |
| 	}
 | |
| 
 | |
| 	function getHead(strURL, fncCallback, fncError) {
 | |
| 		var oHTTP = createRequest();
 | |
| 		if (oHTTP) {
 | |
| 			if (fncCallback) {
 | |
| 				if (typeof(oHTTP.onload) != "undefined") {
 | |
| 					oHTTP.onload = function() {
 | |
| 						if (oHTTP.status == "200") {
 | |
| 							fncCallback(this);
 | |
| 						} else {
 | |
| 							if (fncError) fncError();
 | |
| 						}
 | |
| 						oHTTP = null;
 | |
| 					};
 | |
| 				} else {
 | |
| 					oHTTP.onreadystatechange = function() {
 | |
| 						if (oHTTP.readyState == 4) {
 | |
| 							if (oHTTP.status == "200") {
 | |
| 								fncCallback(this);
 | |
| 							} else {
 | |
| 								if (fncError) fncError();
 | |
| 							}
 | |
| 							oHTTP = null;
 | |
| 						}
 | |
| 					};
 | |
| 				}
 | |
| 			}
 | |
| 			oHTTP.open("HEAD", strURL, true);
 | |
| 			oHTTP.send(null);
 | |
| 		} else {
 | |
| 			if (fncError) fncError();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function sendRequest(strURL, fncCallback, fncError, aRange, bAcceptRanges, iFileSize) {
 | |
| 		var oHTTP = createRequest();
 | |
| 		if (oHTTP) {
 | |
| 
 | |
| 			var iDataOffset = 0;
 | |
| 			if (aRange && !bAcceptRanges) {
 | |
| 				iDataOffset = aRange[0];
 | |
| 			}
 | |
| 			var iDataLen = 0;
 | |
| 			if (aRange) {
 | |
| 				iDataLen = aRange[1]-aRange[0]+1;
 | |
| 			}
 | |
| 
 | |
| 			if (fncCallback) {
 | |
| 				if (typeof(oHTTP.onload) != "undefined") {
 | |
| 					oHTTP.onload = function() {
 | |
| 
 | |
| 						if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") {
 | |
| 							this.binaryResponse = new BinaryFile(this.responseText, iDataOffset, iDataLen);
 | |
| 							this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
 | |
| 							fncCallback(this);
 | |
| 						} else {
 | |
| 							if (fncError) fncError();
 | |
| 						}
 | |
| 						oHTTP = null;
 | |
| 					};
 | |
| 				} else {
 | |
| 					oHTTP.onreadystatechange = function() {
 | |
| 						if (oHTTP.readyState == 4) {
 | |
| 							if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") {
 | |
| 								this.binaryResponse = new BinaryFile(oHTTP.responseBody, iDataOffset, iDataLen);
 | |
| 								this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
 | |
| 								fncCallback(this);
 | |
| 							} else {
 | |
| 								if (fncError) fncError();
 | |
| 							}
 | |
| 							oHTTP = null;
 | |
| 						}
 | |
| 					};
 | |
| 				}
 | |
| 			}
 | |
| 			oHTTP.open("GET", strURL, true);
 | |
| 
 | |
| 			if (oHTTP.overrideMimeType) oHTTP.overrideMimeType('text/plain; charset=x-user-defined');
 | |
| 
 | |
| 			if (aRange && bAcceptRanges) {
 | |
| 				oHTTP.setRequestHeader("Range", "bytes=" + aRange[0] + "-" + aRange[1]);
 | |
| 			}
 | |
| 
 | |
| 			oHTTP.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT");
 | |
| 
 | |
| 			oHTTP.send(null);
 | |
| 		} else {
 | |
| 			if (fncError) fncError();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return function(strURL, fncCallback, fncError, aRange) {
 | |
| 
 | |
| 		if (aRange) {
 | |
| 			getHead(
 | |
| 				strURL, 
 | |
| 				function(oHTTP) {
 | |
| 					var iLength = parseInt(oHTTP.getResponseHeader("Content-Length"),10);
 | |
| 					var strAcceptRanges = oHTTP.getResponseHeader("Accept-Ranges");
 | |
| 
 | |
| 					var iStart, iEnd;
 | |
| 					iStart = aRange[0];
 | |
| 					if (aRange[0] < 0) 
 | |
| 						iStart += iLength;
 | |
| 					iEnd = iStart + aRange[1] - 1;
 | |
| 
 | |
| 					sendRequest(strURL, fncCallback, fncError, [iStart, iEnd], (strAcceptRanges == "bytes"), iLength);
 | |
| 				}
 | |
| 			);
 | |
| 
 | |
| 		} else {
 | |
| 			sendRequest(strURL, fncCallback, fncError);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| }());
 | |
| 
 | |
| 
 | |
| document.write(
 | |
| 	"<script type='text/vbscript'>\r\n"
 | |
| 	+ "Function IEBinary_getByteAt(strBinary, iOffset)\r\n"
 | |
| 	+ "	IEBinary_getByteAt = AscB(MidB(strBinary,iOffset+1,1))\r\n"
 | |
| 	+ "End Function\r\n"
 | |
| 	+ "Function IEBinary_getLength(strBinary)\r\n"
 | |
| 	+ "	IEBinary_getLength = LenB(strBinary)\r\n"
 | |
| 	+ "End Function\r\n"
 | |
| 	+ "</script>\r\n"
 | |
| );
 | |
| 
 | |
| 
 | |
| var EXIF = {};
 | |
| 
 | |
| (function() {
 | |
| 
 | |
| var bDebug = false;
 | |
| 
 | |
| EXIF.Tags = {
 | |
| 
 | |
| 	// version tags
 | |
| 	0x9000 : "ExifVersion",			// EXIF version
 | |
| 	0xA000 : "FlashpixVersion",		// Flashpix format version
 | |
| 
 | |
| 	// colorspace tags
 | |
| 	0xA001 : "ColorSpace",			// Color space information tag
 | |
| 
 | |
| 	// image configuration
 | |
| 	0xA002 : "PixelXDimension",		// Valid width of meaningful image
 | |
| 	0xA003 : "PixelYDimension",		// Valid height of meaningful image
 | |
| 	0x9101 : "ComponentsConfiguration",	// Information about channels
 | |
| 	0x9102 : "CompressedBitsPerPixel",	// Compressed bits per pixel
 | |
| 
 | |
| 	// user information
 | |
| 	0x927C : "MakerNote",			// Any desired information written by the manufacturer
 | |
| 	0x9286 : "UserComment",			// Comments by user
 | |
| 
 | |
| 	// related file
 | |
| 	0xA004 : "RelatedSoundFile",		// Name of related sound file
 | |
| 
 | |
| 	// date and time
 | |
| 	0x9003 : "DateTimeOriginal",		// Date and time when the original image was generated
 | |
| 	0x9004 : "DateTimeDigitized",		// Date and time when the image was stored digitally
 | |
| 	0x9290 : "SubsecTime",			// Fractions of seconds for DateTime
 | |
| 	0x9291 : "SubsecTimeOriginal",		// Fractions of seconds for DateTimeOriginal
 | |
| 	0x9292 : "SubsecTimeDigitized",		// Fractions of seconds for DateTimeDigitized
 | |
| 
 | |
| 	// picture-taking conditions
 | |
| 	0x829A : "ExposureTime",		// Exposure time (in seconds)
 | |
| 	0x829D : "FNumber",			// F number
 | |
| 	0x8822 : "ExposureProgram",		// Exposure program
 | |
| 	0x8824 : "SpectralSensitivity",		// Spectral sensitivity
 | |
| 	0x8827 : "ISOSpeedRatings",		// ISO speed rating
 | |
| 	0x8828 : "OECF",			// Optoelectric conversion factor
 | |
| 	0x9201 : "ShutterSpeedValue",		// Shutter speed
 | |
| 	0x9202 : "ApertureValue",		// Lens aperture
 | |
| 	0x9203 : "BrightnessValue",		// Value of brightness
 | |
| 	0x9204 : "ExposureBias",		// Exposure bias
 | |
| 	0x9205 : "MaxApertureValue",		// Smallest F number of lens
 | |
| 	0x9206 : "SubjectDistance",		// Distance to subject in meters
 | |
| 	0x9207 : "MeteringMode", 		// Metering mode
 | |
| 	0x9208 : "LightSource",			// Kind of light source
 | |
| 	0x9209 : "Flash",			// Flash status
 | |
| 	0x9214 : "SubjectArea",			// Location and area of main subject
 | |
| 	0x920A : "FocalLength",			// Focal length of the lens in mm
 | |
| 	0xA20B : "FlashEnergy",			// Strobe energy in BCPS
 | |
| 	0xA20C : "SpatialFrequencyResponse",	// 
 | |
| 	0xA20E : "FocalPlaneXResolution", 	// Number of pixels in width direction per FocalPlaneResolutionUnit
 | |
| 	0xA20F : "FocalPlaneYResolution", 	// Number of pixels in height direction per FocalPlaneResolutionUnit
 | |
| 	0xA210 : "FocalPlaneResolutionUnit", 	// Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution
 | |
| 	0xA214 : "SubjectLocation",		// Location of subject in image
 | |
| 	0xA215 : "ExposureIndex",		// Exposure index selected on camera
 | |
| 	0xA217 : "SensingMethod", 		// Image sensor type
 | |
| 	0xA300 : "FileSource", 			// Image source (3 == DSC)
 | |
| 	0xA301 : "SceneType", 			// Scene type (1 == directly photographed)
 | |
| 	0xA302 : "CFAPattern",			// Color filter array geometric pattern
 | |
| 	0xA401 : "CustomRendered",		// Special processing
 | |
| 	0xA402 : "ExposureMode",		// Exposure mode
 | |
| 	0xA403 : "WhiteBalance",		// 1 = auto white balance, 2 = manual
 | |
| 	0xA404 : "DigitalZoomRation",		// Digital zoom ratio
 | |
| 	0xA405 : "FocalLengthIn35mmFilm",	// Equivalent foacl length assuming 35mm film camera (in mm)
 | |
| 	0xA406 : "SceneCaptureType",		// Type of scene
 | |
| 	0xA407 : "GainControl",			// Degree of overall image gain adjustment
 | |
| 	0xA408 : "Contrast",			// Direction of contrast processing applied by camera
 | |
| 	0xA409 : "Saturation", 			// Direction of saturation processing applied by camera
 | |
| 	0xA40A : "Sharpness",			// Direction of sharpness processing applied by camera
 | |
| 	0xA40B : "DeviceSettingDescription",	// 
 | |
| 	0xA40C : "SubjectDistanceRange",	// Distance to subject
 | |
| 
 | |
| 	// other tags
 | |
| 	0xA005 : "InteroperabilityIFDPointer",
 | |
| 	0xA420 : "ImageUniqueID"		// Identifier assigned uniquely to each image
 | |
| };
 | |
| 
 | |
| EXIF.TiffTags = {
 | |
| 	0x0100 : "ImageWidth",
 | |
| 	0x0101 : "ImageHeight",
 | |
| 	0x8769 : "ExifIFDPointer",
 | |
| 	0x8825 : "GPSInfoIFDPointer",
 | |
| 	0xA005 : "InteroperabilityIFDPointer",
 | |
| 	0x0102 : "BitsPerSample",
 | |
| 	0x0103 : "Compression",
 | |
| 	0x0106 : "PhotometricInterpretation",
 | |
| 	0x0112 : "Orientation",
 | |
| 	0x0115 : "SamplesPerPixel",
 | |
| 	0x011C : "PlanarConfiguration",
 | |
| 	0x0212 : "YCbCrSubSampling",
 | |
| 	0x0213 : "YCbCrPositioning",
 | |
| 	0x011A : "XResolution",
 | |
| 	0x011B : "YResolution",
 | |
| 	0x0128 : "ResolutionUnit",
 | |
| 	0x0111 : "StripOffsets",
 | |
| 	0x0116 : "RowsPerStrip",
 | |
| 	0x0117 : "StripByteCounts",
 | |
| 	0x0201 : "JPEGInterchangeFormat",
 | |
| 	0x0202 : "JPEGInterchangeFormatLength",
 | |
| 	0x012D : "TransferFunction",
 | |
| 	0x013E : "WhitePoint",
 | |
| 	0x013F : "PrimaryChromaticities",
 | |
| 	0x0211 : "YCbCrCoefficients",
 | |
| 	0x0214 : "ReferenceBlackWhite",
 | |
| 	0x0132 : "DateTime",
 | |
| 	0x010E : "ImageDescription",
 | |
| 	0x010F : "Make",
 | |
| 	0x0110 : "Model",
 | |
| 	0x0131 : "Software",
 | |
| 	0x013B : "Artist",
 | |
| 	0x8298 : "Copyright"
 | |
| }
 | |
| 
 | |
| EXIF.GPSTags = {
 | |
| 	0x0000 : "GPSVersionID",
 | |
| 	0x0001 : "GPSLatitudeRef",
 | |
| 	0x0002 : "GPSLatitude",
 | |
| 	0x0003 : "GPSLongitudeRef",
 | |
| 	0x0004 : "GPSLongitude",
 | |
| 	0x0005 : "GPSAltitudeRef",
 | |
| 	0x0006 : "GPSAltitude",
 | |
| 	0x0007 : "GPSTimeStamp",
 | |
| 	0x0008 : "GPSSatellites",
 | |
| 	0x0009 : "GPSStatus",
 | |
| 	0x000A : "GPSMeasureMode",
 | |
| 	0x000B : "GPSDOP",
 | |
| 	0x000C : "GPSSpeedRef",
 | |
| 	0x000D : "GPSSpeed",
 | |
| 	0x000E : "GPSTrackRef",
 | |
| 	0x000F : "GPSTrack",
 | |
| 	0x0010 : "GPSImgDirectionRef",
 | |
| 	0x0011 : "GPSImgDirection",
 | |
| 	0x0012 : "GPSMapDatum",
 | |
| 	0x0013 : "GPSDestLatitudeRef",
 | |
| 	0x0014 : "GPSDestLatitude",
 | |
| 	0x0015 : "GPSDestLongitudeRef",
 | |
| 	0x0016 : "GPSDestLongitude",
 | |
| 	0x0017 : "GPSDestBearingRef",
 | |
| 	0x0018 : "GPSDestBearing",
 | |
| 	0x0019 : "GPSDestDistanceRef",
 | |
| 	0x001A : "GPSDestDistance",
 | |
| 	0x001B : "GPSProcessingMethod",
 | |
| 	0x001C : "GPSAreaInformation",
 | |
| 	0x001D : "GPSDateStamp",
 | |
| 	0x001E : "GPSDifferential"
 | |
| }
 | |
| 
 | |
| EXIF.StringValues = {
 | |
| 	ExposureProgram : {
 | |
| 		0 : "Not defined",
 | |
| 		1 : "Manual",
 | |
| 		2 : "Normal program",
 | |
| 		3 : "Aperture priority",
 | |
| 		4 : "Shutter priority",
 | |
| 		5 : "Creative program",
 | |
| 		6 : "Action program",
 | |
| 		7 : "Portrait mode",
 | |
| 		8 : "Landscape mode"
 | |
| 	},
 | |
| 	MeteringMode : {
 | |
| 		0 : "Unknown",
 | |
| 		1 : "Average",
 | |
| 		2 : "CenterWeightedAverage",
 | |
| 		3 : "Spot",
 | |
| 		4 : "MultiSpot",
 | |
| 		5 : "Pattern",
 | |
| 		6 : "Partial",
 | |
| 		255 : "Other"
 | |
| 	},
 | |
| 	LightSource : {
 | |
| 		0 : "Unknown",
 | |
| 		1 : "Daylight",
 | |
| 		2 : "Fluorescent",
 | |
| 		3 : "Tungsten (incandescent light)",
 | |
| 		4 : "Flash",
 | |
| 		9 : "Fine weather",
 | |
| 		10 : "Cloudy weather",
 | |
| 		11 : "Shade",
 | |
| 		12 : "Daylight fluorescent (D 5700 - 7100K)",
 | |
| 		13 : "Day white fluorescent (N 4600 - 5400K)",
 | |
| 		14 : "Cool white fluorescent (W 3900 - 4500K)",
 | |
| 		15 : "White fluorescent (WW 3200 - 3700K)",
 | |
| 		17 : "Standard light A",
 | |
| 		18 : "Standard light B",
 | |
| 		19 : "Standard light C",
 | |
| 		20 : "D55",
 | |
| 		21 : "D65",
 | |
| 		22 : "D75",
 | |
| 		23 : "D50",
 | |
| 		24 : "ISO studio tungsten",
 | |
| 		255 : "Other"
 | |
| 	},
 | |
| 	Flash : {
 | |
| 		0x0000 : "Flash did not fire",
 | |
| 		0x0001 : "Flash fired",
 | |
| 		0x0005 : "Strobe return light not detected",
 | |
| 		0x0007 : "Strobe return light detected",
 | |
| 		0x0009 : "Flash fired, compulsory flash mode",
 | |
| 		0x000D : "Flash fired, compulsory flash mode, return light not detected",
 | |
| 		0x000F : "Flash fired, compulsory flash mode, return light detected",
 | |
| 		0x0010 : "Flash did not fire, compulsory flash mode",
 | |
| 		0x0018 : "Flash did not fire, auto mode",
 | |
| 		0x0019 : "Flash fired, auto mode",
 | |
| 		0x001D : "Flash fired, auto mode, return light not detected",
 | |
| 		0x001F : "Flash fired, auto mode, return light detected",
 | |
| 		0x0020 : "No flash function",
 | |
| 		0x0041 : "Flash fired, red-eye reduction mode",
 | |
| 		0x0045 : "Flash fired, red-eye reduction mode, return light not detected",
 | |
| 		0x0047 : "Flash fired, red-eye reduction mode, return light detected",
 | |
| 		0x0049 : "Flash fired, compulsory flash mode, red-eye reduction mode",
 | |
| 		0x004D : "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",
 | |
| 		0x004F : "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",
 | |
| 		0x0059 : "Flash fired, auto mode, red-eye reduction mode",
 | |
| 		0x005D : "Flash fired, auto mode, return light not detected, red-eye reduction mode",
 | |
| 		0x005F : "Flash fired, auto mode, return light detected, red-eye reduction mode"
 | |
| 	},
 | |
| 	SensingMethod : {
 | |
| 		1 : "Not defined",
 | |
| 		2 : "One-chip color area sensor",
 | |
| 		3 : "Two-chip color area sensor",
 | |
| 		4 : "Three-chip color area sensor",
 | |
| 		5 : "Color sequential area sensor",
 | |
| 		7 : "Trilinear sensor",
 | |
| 		8 : "Color sequential linear sensor"
 | |
| 	},
 | |
| 	SceneCaptureType : {
 | |
| 		0 : "Standard",
 | |
| 		1 : "Landscape",
 | |
| 		2 : "Portrait",
 | |
| 		3 : "Night scene"
 | |
| 	},
 | |
| 	SceneType : {
 | |
| 		1 : "Directly photographed"
 | |
| 	},
 | |
| 	CustomRendered : {
 | |
| 		0 : "Normal process",
 | |
| 		1 : "Custom process"
 | |
| 	},
 | |
| 	WhiteBalance : {
 | |
| 		0 : "Auto white balance",
 | |
| 		1 : "Manual white balance"
 | |
| 	},
 | |
| 	GainControl : {
 | |
| 		0 : "None",
 | |
| 		1 : "Low gain up",
 | |
| 		2 : "High gain up",
 | |
| 		3 : "Low gain down",
 | |
| 		4 : "High gain down"
 | |
| 	},
 | |
| 	Contrast : {
 | |
| 		0 : "Normal",
 | |
| 		1 : "Soft",
 | |
| 		2 : "Hard"
 | |
| 	},
 | |
| 	Saturation : {
 | |
| 		0 : "Normal",
 | |
| 		1 : "Low saturation",
 | |
| 		2 : "High saturation"
 | |
| 	},
 | |
| 	Sharpness : {
 | |
| 		0 : "Normal",
 | |
| 		1 : "Soft",
 | |
| 		2 : "Hard"
 | |
| 	},
 | |
| 	SubjectDistanceRange : {
 | |
| 		0 : "Unknown",
 | |
| 		1 : "Macro",
 | |
| 		2 : "Close view",
 | |
| 		3 : "Distant view"
 | |
| 	},
 | |
| 	FileSource : {
 | |
| 		3 : "DSC"
 | |
| 	},
 | |
| 
 | |
| 	Components : {
 | |
| 		0 : "",
 | |
| 		1 : "Y",
 | |
| 		2 : "Cb",
 | |
| 		3 : "Cr",
 | |
| 		4 : "R",
 | |
| 		5 : "G",
 | |
| 		6 : "B"
 | |
| 	}
 | |
| }
 | |
| 
 | |
| function addEvent(oElement, strEvent, fncHandler) 
 | |
| {
 | |
| 	if (oElement.addEventListener) { 
 | |
| 		oElement.addEventListener(strEvent, fncHandler, false); 
 | |
| 	} else if (oElement.attachEvent) { 
 | |
| 		oElement.attachEvent("on" + strEvent, fncHandler); 
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| function imageHasData(oImg) 
 | |
| {
 | |
| 	return !!(oImg.exifdata);
 | |
| }
 | |
| 
 | |
| function getImageData(oImg, fncCallback) 
 | |
| {
 | |
| 	BinaryAjax(
 | |
| 		oImg.src,
 | |
| 		function(oHTTP) {
 | |
| 			var oEXIF = findEXIFinJPEG(oHTTP.binaryResponse);
 | |
| 			oImg.exifdata = oEXIF || {};
 | |
| 			if (fncCallback) fncCallback();
 | |
| 		}
 | |
| 	)
 | |
| }
 | |
| 
 | |
| function findEXIFinJPEG(oFile) {
 | |
| 	var aMarkers = [];
 | |
| 
 | |
| 	if (oFile.getByteAt(0) != 0xFF || oFile.getByteAt(1) != 0xD8) {
 | |
| 		return false; // not a valid jpeg
 | |
| 	}
 | |
| 
 | |
| 	var iOffset = 2;
 | |
| 	var iLength = oFile.getLength();
 | |
| 	while (iOffset < iLength) {
 | |
| 		if (oFile.getByteAt(iOffset) != 0xFF) {
 | |
| 			if (bDebug) console.log("Not a valid marker at offset " + iOffset + ", found: " + oFile.getByteAt(iOffset));
 | |
| 			return false; // not a valid marker, something is wrong
 | |
| 		}
 | |
| 
 | |
| 		var iMarker = oFile.getByteAt(iOffset+1);
 | |
| 
 | |
| 		// we could implement handling for other markers here, 
 | |
| 		// but we're only looking for 0xFFE1 for EXIF data
 | |
| 
 | |
| 		if (iMarker == 22400) {
 | |
| 			if (bDebug) console.log("Found 0xFFE1 marker");
 | |
| 			return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset+2, true)-2);
 | |
| 			iOffset += 2 + oFile.getShortAt(iOffset+2, true);
 | |
| 
 | |
| 		} else if (iMarker == 225) {
 | |
| 			// 0xE1 = Application-specific 1 (for EXIF)
 | |
| 			if (bDebug) console.log("Found 0xFFE1 marker");
 | |
| 			return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset+2, true)-2);
 | |
| 
 | |
| 		} else {
 | |
| 			iOffset += 2 + oFile.getShortAt(iOffset+2, true);
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| function readTags(oFile, iTIFFStart, iDirStart, oStrings, bBigEnd) 
 | |
| {
 | |
| 	var iEntries = oFile.getShortAt(iDirStart, bBigEnd);
 | |
| 	var oTags = {};
 | |
| 	for (var i=0;i<iEntries;i++) {
 | |
| 		var iEntryOffset = iDirStart + i*12 + 2;
 | |
| 		var strTag = oStrings[oFile.getShortAt(iEntryOffset, bBigEnd)];
 | |
| 		if (!strTag && bDebug) console.log("Unknown tag: " + oFile.getShortAt(iEntryOffset, bBigEnd));
 | |
| 		oTags[strTag] = readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd);
 | |
| 	}
 | |
| 	return oTags;
 | |
| }
 | |
| 
 | |
| 
 | |
| function readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd)
 | |
| {
 | |
| 	var iType = oFile.getShortAt(iEntryOffset+2, bBigEnd);
 | |
| 	var iNumValues = oFile.getLongAt(iEntryOffset+4, bBigEnd);
 | |
| 	var iValueOffset = oFile.getLongAt(iEntryOffset+8, bBigEnd) + iTIFFStart;
 | |
| 
 | |
| 	switch (iType) {
 | |
| 		case 1: // byte, 8-bit unsigned int
 | |
| 		case 7: // undefined, 8-bit byte, value depending on field
 | |
| 			if (iNumValues == 1) {
 | |
| 				return oFile.getByteAt(iEntryOffset + 8, bBigEnd);
 | |
| 			} else {
 | |
| 				var iValOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
 | |
| 				var aVals = [];
 | |
| 				for (var n=0;n<iNumValues;n++) {
 | |
| 					aVals[n] = oFile.getByteAt(iValOffset + n);
 | |
| 				}
 | |
| 				return aVals;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case 2: // ascii, 8-bit byte
 | |
| 			var iStringOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
 | |
| 			return oFile.getStringAt(iStringOffset, iNumValues-1);
 | |
| 			break;
 | |
| 
 | |
| 		case 3: // short, 16 bit int
 | |
| 			if (iNumValues == 1) {
 | |
| 				return oFile.getShortAt(iEntryOffset + 8, bBigEnd);
 | |
| 			} else {
 | |
| 				var iValOffset = iNumValues > 2 ? iValueOffset : (iEntryOffset + 8);
 | |
| 				var aVals = [];
 | |
| 				for (var n=0;n<iNumValues;n++) {
 | |
| 					aVals[n] = oFile.getShortAt(iValOffset + 2*n, bBigEnd);
 | |
| 				}
 | |
| 				return aVals;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case 4: // long, 32 bit int
 | |
| 			if (iNumValues == 1) {
 | |
| 				return oFile.getLongAt(iEntryOffset + 8, bBigEnd);
 | |
| 			} else {
 | |
| 				var aVals = [];
 | |
| 				for (var n=0;n<iNumValues;n++) {
 | |
| 					aVals[n] = oFile.getLongAt(iValueOffset + 4*n, bBigEnd);
 | |
| 				}
 | |
| 				return aVals;
 | |
| 			}
 | |
| 			break;
 | |
| 		case 5:	// rational = two long values, first is numerator, second is denominator
 | |
| 			if (iNumValues == 1) {
 | |
| 				return oFile.getLongAt(iValueOffset, bBigEnd) / oFile.getLongAt(iValueOffset+4, bBigEnd);
 | |
| 			} else {
 | |
| 				var aVals = [];
 | |
| 				for (var n=0;n<iNumValues;n++) {
 | |
| 					aVals[n] = oFile.getLongAt(iValueOffset + 8*n, bBigEnd) / oFile.getLongAt(iValueOffset+4 + 8*n, bBigEnd);
 | |
| 				}
 | |
| 				return aVals;
 | |
| 			}
 | |
| 			break;
 | |
| 		case 9: // slong, 32 bit signed int
 | |
| 			if (iNumValues == 1) {
 | |
| 				return oFile.getSLongAt(iEntryOffset + 8, bBigEnd);
 | |
| 			} else {
 | |
| 				var aVals = [];
 | |
| 				for (var n=0;n<iNumValues;n++) {
 | |
| 					aVals[n] = oFile.getSLongAt(iValueOffset + 4*n, bBigEnd);
 | |
| 				}
 | |
| 				return aVals;
 | |
| 			}
 | |
| 			break;
 | |
| 		case 10: // signed rational, two slongs, first is numerator, second is denominator
 | |
| 			if (iNumValues == 1) {
 | |
| 				return oFile.getSLongAt(iValueOffset, bBigEnd) / oFile.getSLongAt(iValueOffset+4, bBigEnd);
 | |
| 			} else {
 | |
| 				var aVals = [];
 | |
| 				for (var n=0;n<iNumValues;n++) {
 | |
| 					aVals[n] = oFile.getSLongAt(iValueOffset + 8*n, bBigEnd) / oFile.getSLongAt(iValueOffset+4 + 8*n, bBigEnd);
 | |
| 				}
 | |
| 				return aVals;
 | |
| 			}
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| function readEXIFData(oFile, iStart, iLength) 
 | |
| {
 | |
| 	if (oFile.getStringAt(iStart, 4) != "Exif") {
 | |
| 		if (bDebug) console.log("Not valid EXIF data! " + oFile.getStringAt(iStart, 4));
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	var bBigEnd;
 | |
| 
 | |
| 	var iTIFFOffset = iStart + 6;
 | |
| 
 | |
| 	// test for TIFF validity and endianness
 | |
| 	if (oFile.getShortAt(iTIFFOffset) == 0x4949) {
 | |
| 		bBigEnd = false;
 | |
| 	} else if (oFile.getShortAt(iTIFFOffset) == 0x4D4D) {
 | |
| 		bBigEnd = true;
 | |
| 	} else {
 | |
| 		if (bDebug) console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (oFile.getShortAt(iTIFFOffset+2, bBigEnd) != 0x002A) {
 | |
| 		if (bDebug) console.log("Not valid TIFF data! (no 0x002A)");
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (oFile.getLongAt(iTIFFOffset+4, bBigEnd) != 0x00000008) {
 | |
| 		if (bDebug) console.log("Not valid TIFF data! (First offset not 8)", oFile.getShortAt(iTIFFOffset+4, bBigEnd));
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	var oTags = readTags(oFile, iTIFFOffset, iTIFFOffset+8, EXIF.TiffTags, bBigEnd);
 | |
| 
 | |
| 	if (oTags.ExifIFDPointer) {
 | |
| 		var oEXIFTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.ExifIFDPointer, EXIF.Tags, bBigEnd);
 | |
| 		for (var strTag in oEXIFTags) {
 | |
| 			switch (strTag) {
 | |
| 				case "LightSource" :
 | |
| 				case "Flash" :
 | |
| 				case "MeteringMode" :
 | |
| 				case "ExposureProgram" :
 | |
| 				case "SensingMethod" :
 | |
| 				case "SceneCaptureType" :
 | |
| 				case "SceneType" :
 | |
| 				case "CustomRendered" :
 | |
| 				case "WhiteBalance" : 
 | |
| 				case "GainControl" : 
 | |
| 				case "Contrast" :
 | |
| 				case "Saturation" :
 | |
| 				case "Sharpness" : 
 | |
| 				case "SubjectDistanceRange" :
 | |
| 				case "FileSource" :
 | |
| 					oEXIFTags[strTag] = EXIF.StringValues[strTag][oEXIFTags[strTag]];
 | |
| 					break;
 | |
| 	
 | |
| 				case "ExifVersion" :
 | |
| 				case "FlashpixVersion" :
 | |
| 					oEXIFTags[strTag] = String.fromCharCode(oEXIFTags[strTag][0], oEXIFTags[strTag][1], oEXIFTags[strTag][2], oEXIFTags[strTag][3]);
 | |
| 					break;
 | |
| 	
 | |
| 				case "ComponentsConfiguration" : 
 | |
| 					oEXIFTags[strTag] = 
 | |
| 						EXIF.StringValues.Components[oEXIFTags[strTag][0]]
 | |
| 						+ EXIF.StringValues.Components[oEXIFTags[strTag][1]]
 | |
| 						+ EXIF.StringValues.Components[oEXIFTags[strTag][2]]
 | |
| 						+ EXIF.StringValues.Components[oEXIFTags[strTag][3]];
 | |
| 					break;
 | |
| 			}
 | |
| 			oTags[strTag] = oEXIFTags[strTag];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (oTags.GPSInfoIFDPointer) {
 | |
| 		var oGPSTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.GPSInfoIFDPointer, EXIF.GPSTags, bBigEnd);
 | |
| 		for (var strTag in oGPSTags) {
 | |
| 			switch (strTag) {
 | |
| 				case "GPSVersionID" : 
 | |
| 					oGPSTags[strTag] = oGPSTags[strTag][0] 
 | |
| 						+ "." + oGPSTags[strTag][1] 
 | |
| 						+ "." + oGPSTags[strTag][2] 
 | |
| 						+ "." + oGPSTags[strTag][3];
 | |
| 					break;
 | |
| 			}
 | |
| 			oTags[strTag] = oGPSTags[strTag];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return oTags;
 | |
| }
 | |
| 
 | |
| 
 | |
| EXIF.getData = function(oImg, fncCallback) 
 | |
| {
 | |
| 	if (!oImg.complete) return false;
 | |
| 	if (!imageHasData(oImg)) {
 | |
| 		getImageData(oImg, fncCallback);
 | |
| 	} else {
 | |
| 		if (fncCallback) fncCallback();
 | |
| 	}
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| EXIF.getTag = function(oImg, strTag) 
 | |
| {
 | |
| 	if (!imageHasData(oImg)) return;
 | |
| 	return oImg.exifdata[strTag];
 | |
| }
 | |
| 
 | |
| EXIF.getAllTags = function(oImg) 
 | |
| {
 | |
| 	if (!imageHasData(oImg)) return {};
 | |
| 	var oData = oImg.exifdata;
 | |
| 	var oAllTags = {};
 | |
| 	for (var a in oData) {
 | |
| 		if (oData.hasOwnProperty(a)) {
 | |
| 			oAllTags[a] = oData[a];
 | |
| 		}
 | |
| 	}
 | |
| 	return oAllTags;
 | |
| }
 | |
| 
 | |
| EXIF.pretty = function(oImg) 
 | |
| {
 | |
| 	if (!imageHasData(oImg)) return "";
 | |
| 	var oData = oImg.exifdata;
 | |
| 	var strPretty = "";
 | |
| 	for (var a in oData) {
 | |
| 		if (oData.hasOwnProperty(a)) {
 | |
| 			if (typeof oData[a] == "object") {
 | |
| 				strPretty += a + " : [" + oData[a].length + " values]\r\n";
 | |
| 			} else {
 | |
| 				strPretty += a + " : " + oData[a] + "\r\n";
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return strPretty;
 | |
| }
 | |
| 
 | |
| EXIF.readFromBinaryFile = function(oFile) {
 | |
| 	return findEXIFinJPEG(oFile);
 | |
| }
 | |
| 
 | |
| function loadAllImages() 
 | |
| {
 | |
| 	var aImages = document.getElementsByTagName("img");
 | |
| 	for (var i=0;i<aImages.length;i++) {
 | |
| 		if (aImages[i].getAttribute("exif") == "true") {
 | |
| 			if (!aImages[i].complete) {
 | |
| 				addEvent(aImages[i], "load", 
 | |
| 					function() {
 | |
| 						EXIF.getData(this);
 | |
| 					}
 | |
| 				); 
 | |
| 			} else {
 | |
| 				EXIF.getData(aImages[i]);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // automatically load exif data for all images with exif=true when doc is ready
 | |
| jQuery(document).ready(loadAllImages);
 | |
| 
 | |
| // load data for images manually
 | |
| jQuery.fn.exifLoad = function(fncCallback) {
 | |
| 	return this.each(function() {
 | |
| 		EXIF.getData(this, fncCallback)
 | |
| 	});
 | |
| }
 | |
| 
 | |
| jQuery.fn.exif = function(strTag) {
 | |
| 	var aStrings = [];
 | |
| 	this.each(function() {
 | |
| 		aStrings.push(EXIF.getTag(this, strTag));
 | |
| 	});
 | |
| 	return aStrings;
 | |
| }
 | |
| 
 | |
| jQuery.fn.exifAll = function() {
 | |
| 	var aStrings = [];
 | |
| 	this.each(function() {
 | |
| 		aStrings.push(EXIF.getAllTags(this));
 | |
| 	});
 | |
| 	return aStrings;
 | |
| }
 | |
| 
 | |
| jQuery.fn.exifPretty = function() {
 | |
| 	var aStrings = [];
 | |
| 	this.each(function() {
 | |
| 		aStrings.push(EXIF.pretty(this));
 | |
| 	});
 | |
| 	return aStrings;
 | |
| }
 | |
| 
 | |
| 
 | |
| })();
 | |
| 
 | |
| 
 | |
| })(); |