exif.min.js 16 KB

1
  1. (function(){var debug=false;var root=this;var EXIF=function(obj){if(obj instanceof EXIF){return obj}if(!(this instanceof EXIF)){return new EXIF(obj)}this.EXIFwrapped=obj};if(typeof exports!=='undefined'){if(typeof module!=='undefined'&&module.exports){exports=module.exports=EXIF}exports.EXIF=EXIF}else{root.EXIF=EXIF}var ExifTags=EXIF.Tags={0x9000:"ExifVersion",0xA000:"FlashpixVersion",0xA001:"ColorSpace",0xA002:"PixelXDimension",0xA003:"PixelYDimension",0x9101:"ComponentsConfiguration",0x9102:"CompressedBitsPerPixel",0x927C:"MakerNote",0x9286:"UserComment",0xA004:"RelatedSoundFile",0x9003:"DateTimeOriginal",0x9004:"DateTimeDigitized",0x9290:"SubsecTime",0x9291:"SubsecTimeOriginal",0x9292:"SubsecTimeDigitized",0x829A:"ExposureTime",0x829D:"FNumber",0x8822:"ExposureProgram",0x8824:"SpectralSensitivity",0x8827:"ISOSpeedRatings",0x8828:"OECF",0x9201:"ShutterSpeedValue",0x9202:"ApertureValue",0x9203:"BrightnessValue",0x9204:"ExposureBias",0x9205:"MaxApertureValue",0x9206:"SubjectDistance",0x9207:"MeteringMode",0x9208:"LightSource",0x9209:"Flash",0x9214:"SubjectArea",0x920A:"FocalLength",0xA20B:"FlashEnergy",0xA20C:"SpatialFrequencyResponse",0xA20E:"FocalPlaneXResolution",0xA20F:"FocalPlaneYResolution",0xA210:"FocalPlaneResolutionUnit",0xA214:"SubjectLocation",0xA215:"ExposureIndex",0xA217:"SensingMethod",0xA300:"FileSource",0xA301:"SceneType",0xA302:"CFAPattern",0xA401:"CustomRendered",0xA402:"ExposureMode",0xA403:"WhiteBalance",0xA404:"DigitalZoomRation",0xA405:"FocalLengthIn35mmFilm",0xA406:"SceneCaptureType",0xA407:"GainControl",0xA408:"Contrast",0xA409:"Saturation",0xA40A:"Sharpness",0xA40B:"DeviceSettingDescription",0xA40C:"SubjectDistanceRange",0xA005:"InteroperabilityIFDPointer",0xA420:"ImageUniqueID"};var TiffTags=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"};var GPSTags=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"};var StringValues=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(element,event,handler){if(element.addEventListener){element.addEventListener(event,handler,false)}else if(element.attachEvent){element.attachEvent("on"+event,handler)}}function imageHasData(img){return!!(img.exifdata)}function base64ToArrayBuffer(base64,contentType){contentType=contentType||base64.match(/^data\:([^\;]+)\;base64,/mi)[1]||'';base64=base64.replace(/^data\:([^\;]+)\;base64,/gmi,'');var binary=atob(base64);var len=binary.length;var buffer=new ArrayBuffer(len);var view=new Uint8Array(buffer);for(var i=0;i<len;i+=1){view[i]=binary.charCodeAt(i)}return buffer}function objectURLToBlob(url,callback){var http=new XMLHttpRequest();http.open("GET",url,true);http.responseType="blob";http.onload=function(e){if(this.status==200||this.status===0){callback(this.response)}};http.send()}function getImageData(img,callback){function handleBinaryFile(binFile){var data=findEXIFinJPEG(binFile);var iptcdata=findIPTCinJPEG(binFile);img.exifdata=data||{};img.iptcdata=iptcdata||{};if(callback){callback.call(img)}}if(img.src){if(/^data\:/i.test(img.src)){var arrayBuffer=base64ToArrayBuffer(img.src);handleBinaryFile(arrayBuffer)}else if(/^blob\:/i.test(img.src)){var fileReader=new FileReader();fileReader.onload=function(e){handleBinaryFile(e.target.result)};objectURLToBlob(img.src,function(blob){fileReader.readAsArrayBuffer(blob)})}else{var http=new XMLHttpRequest();http.onload=function(){if(this.status==200||this.status===0){handleBinaryFile(http.response)}else{throw "Could not load image"}http=null};http.open("GET",img.src,true);http.responseType="arraybuffer";http.send(null)}}else if(window.FileReader&&(img instanceof window.Blob||img instanceof window.File)){var fileReader=new FileReader();fileReader.onload=function(e){if(debug){console.log("Got file of length "+e.target.result.byteLength)}handleBinaryFile(e.target.result)};fileReader.readAsArrayBuffer(img)}}function findEXIFinJPEG(file){var dataView=new DataView(file);if(debug){console.log("Got file of length "+file.byteLength)}if((dataView.getUint8(0)!=0xFF)||(dataView.getUint8(1)!=0xD8)){if(debug){console.log("Not a valid JPEG")}return false;}var offset=2,length=file.byteLength,marker;while(offset<length){if(dataView.getUint8(offset)!=0xFF){if(debug){console.log("Not a valid marker at offset "+offset+", found: "+dataView.getUint8(offset))}return false;}marker=dataView.getUint8(offset+1);if(debug){console.log(marker)}if(marker==225){if(debug){console.log("Found 0xFFE1 marker")}return readEXIFData(dataView,offset+4,dataView.getUint16(offset+2)-2);}else{offset+=2+dataView.getUint16(offset+2)}}}function findIPTCinJPEG(file){var dataView=new DataView(file);if(debug){console.log("Got file of length "+file.byteLength)}if((dataView.getUint8(0)!=0xFF)||(dataView.getUint8(1)!=0xD8)){if(debug){console.log("Not a valid JPEG")}return false;}var offset=2,length=file.byteLength;var isFieldSegmentStart=function(dataView,offset){return(dataView.getUint8(offset)===0x38&&dataView.getUint8(offset+1)===0x42&&dataView.getUint8(offset+2)===0x49&&dataView.getUint8(offset+3)===0x4D&&dataView.getUint8(offset+4)===0x04&&dataView.getUint8(offset+5)===0x04)};while(offset<length){if(isFieldSegmentStart(dataView,offset)){var nameHeaderLength=dataView.getUint8(offset+7);if(nameHeaderLength%2!==0){nameHeaderLength+=1}if(nameHeaderLength===0){nameHeaderLength=4}var startOffset=offset+8+nameHeaderLength;var sectionLength=dataView.getUint16(offset+6+nameHeaderLength);return readIPTCData(file,startOffset,sectionLength);break}offset+=1}}var IptcFieldMap={0x78:'caption',0x6E:'credit',0x19:'keywords',0x37:'dateCreated',0x50:'byline',0x55:'bylineTitle',0x7A:'captionWriter',0x69:'headline',0x74:'copyright',0x0F:'category'};function readIPTCData(file,startOffset,sectionLength){var dataView=new DataView(file);var data={};var fieldValue,fieldName,dataSize,segmentType,segmentSize;var segmentStartPos=startOffset;while(segmentStartPos<startOffset+sectionLength){if(dataView.getUint8(segmentStartPos)===0x1C&&dataView.getUint8(segmentStartPos+1)===0x02){segmentType=dataView.getUint8(segmentStartPos+2);if(segmentType in IptcFieldMap){dataSize=dataView.getInt16(segmentStartPos+3);segmentSize=dataSize+5;fieldName=IptcFieldMap[segmentType];fieldValue=getStringFromDB(dataView,segmentStartPos+5,dataSize);if(data.hasOwnProperty(fieldName)){if(data[fieldName]instanceof Array){data[fieldName].push(fieldValue)}else{data[fieldName]=[data[fieldName],fieldValue]}}else{data[fieldName]=fieldValue}}}segmentStartPos+=1}return data}function readTags(file,tiffStart,dirStart,strings,bigEnd){var entries=file.getUint16(dirStart,!bigEnd),tags={},entryOffset,tag,i;for(i=0;i<entries;i+=1){entryOffset=dirStart+i*12+2;tag=strings[file.getUint16(entryOffset,!bigEnd)];if(!tag&&debug){console.log("Unknown tag: "+file.getUint16(entryOffset,!bigEnd))}tags[tag]=readTagValue(file,entryOffset,tiffStart,dirStart,bigEnd)}return tags}function readTagValue(file,entryOffset,tiffStart,dirStart,bigEnd){var type=file.getUint16(entryOffset+2,!bigEnd),numValues=file.getUint32(entryOffset+4,!bigEnd),valueOffset=file.getUint32(entryOffset+8,!bigEnd)+tiffStart,offset,vals,val,n,numerator,denominator;switch(type){case 1:case 7:if(numValues==1){return file.getUint8(entryOffset+8,!bigEnd)}else{offset=numValues>4?valueOffset:(entryOffset+8);vals=[];for(n=0;n<numValues;n+=1){vals[n]=file.getUint8(offset+n)}return vals}case 2:offset=numValues>4?valueOffset:(entryOffset+8);return getStringFromDB(file,offset,numValues-1);case 3:if(numValues==1){return file.getUint16(entryOffset+8,!bigEnd)}else{offset=numValues>2?valueOffset:(entryOffset+8);vals=[];for(n=0;n<numValues;n+=1){vals[n]=file.getUint16(offset+2*n,!bigEnd)}return vals}case 4:if(numValues==1){return file.getUint32(entryOffset+8,!bigEnd)}else{vals=[];for(n=0;n<numValues;n+=1){vals[n]=file.getUint32(valueOffset+4*n,!bigEnd)}return vals}case 5:if(numValues==1){numerator=file.getUint32(valueOffset,!bigEnd);denominator=file.getUint32(valueOffset+4,!bigEnd);val=new Number(numerator/denominator);val.numerator=numerator;val.denominator=denominator;return val}else{vals=[];for(n=0;n<numValues;n+=1){numerator=file.getUint32(valueOffset+8*n,!bigEnd);denominator=file.getUint32(valueOffset+4+8*n,!bigEnd);vals[n]=new Number(numerator/denominator);vals[n].numerator=numerator;vals[n].denominator=denominator}return vals}case 9:if(numValues==1){return file.getInt32(entryOffset+8,!bigEnd)}else{vals=[];for(n=0;n<numValues;n+=1){vals[n]=file.getInt32(valueOffset+4*n,!bigEnd)}return vals}case 10:if(numValues==1){return file.getInt32(valueOffset,!bigEnd)/file.getInt32(valueOffset+4,!bigEnd)}else{vals=[];for(n=0;n<numValues;n+=1){vals[n]=file.getInt32(valueOffset+8*n,!bigEnd)/file.getInt32(valueOffset+4+8*n,!bigEnd)}return vals}}}function getStringFromDB(buffer,start,length){var outstr="";for(n=start;n<start+length;n+=1){outstr+=String.fromCharCode(buffer.getUint8(n))}return outstr}function readEXIFData(file,start){if(getStringFromDB(file,start,4)!="Exif"){if(debug){console.log("Not valid EXIF data! "+getStringFromDB(file,start,4))}return false}var bigEnd,tags,tag,exifData,gpsData,tiffOffset=start+6;if(file.getUint16(tiffOffset)==0x4949){bigEnd=false}else if(file.getUint16(tiffOffset)==0x4D4D){bigEnd=true}else{if(debug){console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)")}return false}if(file.getUint16(tiffOffset+2,!bigEnd)!=0x002A){if(debug){console.log("Not valid TIFF data! (no 0x002A)")}return false}var firstIFDOffset=file.getUint32(tiffOffset+4,!bigEnd);if(firstIFDOffset<0x00000008){if(debug){console.log("Not valid TIFF data! (First offset less than 8)",file.getUint32(tiffOffset+4,!bigEnd))}return false}tags=readTags(file,tiffOffset,tiffOffset+firstIFDOffset,TiffTags,bigEnd);if(tags.ExifIFDPointer){exifData=readTags(file,tiffOffset,tiffOffset+tags.ExifIFDPointer,ExifTags,bigEnd);for(tag in exifData){switch(tag){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":exifData[tag]=StringValues[tag][exifData[tag]];break;case "ExifVersion":case "FlashpixVersion":exifData[tag]=String.fromCharCode(exifData[tag][0],exifData[tag][1],exifData[tag][2],exifData[tag][3]);break;case "ComponentsConfiguration":exifData[tag]=StringValues.Components[exifData[tag][0]]+StringValues.Components[exifData[tag][1]]+StringValues.Components[exifData[tag][2]]+StringValues.Components[exifData[tag][3]];break}tags[tag]=exifData[tag]}}if(tags.GPSInfoIFDPointer){gpsData=readTags(file,tiffOffset,tiffOffset+tags.GPSInfoIFDPointer,GPSTags,bigEnd);for(tag in gpsData){switch(tag){case "GPSVersionID":gpsData[tag]=gpsData[tag][0]+"."+gpsData[tag][1]+"."+gpsData[tag][2]+"."+gpsData[tag][3];break}tags[tag]=gpsData[tag]}}return tags}EXIF.getData=function(img,callback){if((img instanceof Image||img instanceof HTMLImageElement)&&!img.complete){return false}if(!imageHasData(img)){getImageData(img,callback)}else{if(callback){callback.call(img)}}return true};EXIF.getTag=function(img,tag){if(!imageHasData(img)){return}return img.exifdata[tag]};EXIF.getAllTags=function(img){if(!imageHasData(img)){return{}}var a,data=img.exifdata,tags={};for(a in data){if(data.hasOwnProperty(a)){tags[a]=data[a]}}return tags};EXIF.pretty=function(img){if(!imageHasData(img)){return ""}var a,data=img.exifdata,strPretty="";for(a in data){if(data.hasOwnProperty(a)){if(typeof data[a]=="object"){if(data[a]instanceof Number){strPretty+=a+" : "+data[a]+" ["+data[a].numerator+"/"+data[a].denominator+"]\r\n"}else{strPretty+=a+" : ["+data[a].length+" values]\r\n"}}else{strPretty+=a+" : "+data[a]+"\r\n"}}}return strPretty};EXIF.readFromBinaryFile=function(file){return findEXIFinJPEG(file)};if(typeof define==='function'&&define.amd){define('exif-js',[],function(){return EXIF})}}.call(this));