@evshiron/exifr
Version:
📷 The fastest and most versatile JavaScript EXIF reading library.
2 lines (1 loc) • 30.6 kB
JavaScript
function e(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}var t="undefined"!=typeof self?self:global;const i="undefined"!=typeof navigator,s=i&&"undefined"==typeof HTMLImageElement,n=!("undefined"==typeof global||"undefined"==typeof process||!process.versions||!process.versions.node),r=t.Buffer,a=!!r,h=e=>void 0!==e;function l(e){return void 0===e||(e instanceof Map?0===e.size:0===Object.values(e).filter(h).length)}function f(e){let t=new Error(e);throw delete t.stack,t}function o(e){let t=function(e){let t=0;return e.ifd0.enabled&&(t+=1024),e.exif.enabled&&(t+=2048),e.makerNote&&(t+=2048),e.userComment&&(t+=1024),e.gps.enabled&&(t+=512),e.interop.enabled&&(t+=100),e.ifd1.enabled&&(t+=1024),t+2048}(e);return e.jfif.enabled&&(t+=50),e.xmp.enabled&&(t+=2e4),e.iptc.enabled&&(t+=14e3),e.icc.enabled&&(t+=6e3),t}const u=e=>String.fromCharCode.apply(null,e),d="undefined"!=typeof TextDecoder?new TextDecoder("utf-8"):void 0;class c{static from(e,t){return e instanceof this&&e.le===t?e:new c(e,void 0,void 0,t)}constructor(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=arguments.length>2?arguments[2]:void 0,s=arguments.length>3?arguments[3]:void 0;if("boolean"==typeof s&&(this.le=s),Array.isArray(e)&&(e=new Uint8Array(e)),0===e)this.byteOffset=0,this.byteLength=0;else if(e instanceof ArrayBuffer){void 0===i&&(i=e.byteLength-t);let s=new DataView(e,t,i);this._swapDataView(s)}else if(e instanceof Uint8Array||e instanceof DataView||e instanceof c){void 0===i&&(i=e.byteLength-t),t+=e.byteOffset,t+i>e.byteOffset+e.byteLength&&f("Creating view outside of available memory in ArrayBuffer");let s=new DataView(e.buffer,t,i);this._swapDataView(s)}else if("number"==typeof e){let t=new DataView(new ArrayBuffer(e));this._swapDataView(t)}else f("Invalid input argument for BufferView: "+e)}_swapArrayBuffer(e){this._swapDataView(new DataView(e))}_swapBuffer(e){this._swapDataView(new DataView(e.buffer,e.byteOffset,e.byteLength))}_swapDataView(e){this.dataView=e,this.buffer=e.buffer,this.byteOffset=e.byteOffset,this.byteLength=e.byteLength}_lengthToEnd(e){return this.byteLength-e}set(e,t){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:c;return e instanceof DataView||e instanceof c?e=new Uint8Array(e.buffer,e.byteOffset,e.byteLength):e instanceof ArrayBuffer&&(e=new Uint8Array(e)),e instanceof Uint8Array||f("BufferView.set(): Invalid data argument."),this.toUint8().set(e,t),new i(this,t,e.byteLength)}subarray(e,t){return t=t||this._lengthToEnd(e),new c(this,e,t)}toUint8(){return new Uint8Array(this.buffer,this.byteOffset,this.byteLength)}getUint8Array(e,t){return new Uint8Array(this.buffer,this.byteOffset+e,t)}getString(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.byteLength,i=this.getUint8Array(e,t);return s=i,d?d.decode(s):a?Buffer.from(s).toString("utf8"):decodeURIComponent(escape(u(s)));var s}getLatin1String(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.byteLength,i=this.getUint8Array(e,t);return u(i)}getUnicodeString(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.byteLength;const i=[];for(let s=0;s<t&&e+s<this.byteLength;s+=2)i.push(this.getUint16(e+s));return u(i)}getInt8(e){return this.dataView.getInt8(e)}getUint8(e){return this.dataView.getUint8(e)}getInt16(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.le;return this.dataView.getInt16(e,t)}getInt32(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.le;return this.dataView.getInt32(e,t)}getUint16(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.le;return this.dataView.getUint16(e,t)}getUint32(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.le;return this.dataView.getUint32(e,t)}getFloat32(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.le;return this.dataView.getFloat32(e,t)}getFloat64(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.le;return this.dataView.getFloat64(e,t)}getFloat(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.le;return this.dataView.getFloat32(e,t)}getDouble(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.le;return this.dataView.getFloat64(e,t)}getUintBytes(e,t,i){switch(t){case 1:return this.getUint8(e,i);case 2:return this.getUint16(e,i);case 4:return this.getUint32(e,i);case 8:return this.getUint64&&this.getUint64(e,i)}}getUint(e,t,i){switch(t){case 8:return this.getUint8(e,i);case 16:return this.getUint16(e,i);case 32:return this.getUint32(e,i);case 64:return this.getUint64&&this.getUint64(e,i)}}toString(e){return this.dataView.toString(e,this.constructor.name)}ensureChunk(){}}function g(e,t){f(`${e} '${t}' was not loaded, try using full build of exifr.`)}class p extends Map{constructor(e){super(),this.kind=e}get(e,t){return this.has(e)||g(this.kind,e),t&&(e in t||function(e,t){f(`Unknown ${e} '${t}'.`)}(this.kind,e),t[e].enabled||g(this.kind,e)),super.get(e)}keyList(){return Array.from(this.keys())}}var m=new p("file parser"),y=new p("segment parser"),b=new p("file reader");let w=t.fetch;function k(e,t){return(s=e).startsWith("data:")||s.length>1e4?O(e,t,"base64"):n&&e.includes("://")?v(e,t,"url",S):n?O(e,t,"fs"):i?v(e,t,"url",S):void f("Invalid input argument");var s}async function v(e,t,i,s){return b.has(i)?O(e,t,i):s?async function(e,t){let i=await t(e);return new c(i)}(e,s):void f(`Parser ${i} is not loaded`)}async function O(e,t,i){let s=new(b.get(i))(e,t);return await s.read(),s}const S=e=>w(e).then((e=>e.arrayBuffer())),A=e=>new Promise(((t,i)=>{let s=new FileReader;s.onloadend=()=>t(s.result||new ArrayBuffer),s.onerror=i,s.readAsArrayBuffer(e)}));class U extends Map{get tagKeys(){return this.allKeys||(this.allKeys=Array.from(this.keys())),this.allKeys}get tagValues(){return this.allValues||(this.allValues=Array.from(this.values())),this.allValues}}function x(e,t,i){let s=new U;for(let[e,t]of i)s.set(e,t);if(Array.isArray(t))for(let i of t)e.set(i,s);else e.set(t,s);return s}function C(e,t,i){let s,n=e.get(t);for(s of i)n.set(s[0],s[1])}const B=new Map,V=new Map,I=new Map,L=["chunked","firstChunkSize","firstChunkSizeNode","firstChunkSizeBrowser","chunkSize","chunkLimit"],T=["jfif","xmp","icc","iptc","ihdr"],z=["tiff",...T],P=["ifd0","ifd1","exif","gps","interop"],F=[...z,...P],j=["makerNote","userComment"],E=["translateKeys","translateValues","reviveValues","multiSegment"],M=[...E,"sanitize","mergeOutput","silentErrors"];class _{get translate(){return this.translateKeys||this.translateValues||this.reviveValues}}class D extends _{get needed(){return this.enabled||this.deps.size>0}constructor(t,i,s,n){if(super(),e(this,"enabled",!1),e(this,"skip",new Set),e(this,"pick",new Set),e(this,"deps",new Set),e(this,"translateKeys",!1),e(this,"translateValues",!1),e(this,"reviveValues",!1),this.key=t,this.enabled=i,this.parse=this.enabled,this.applyInheritables(n),this.canBeFiltered=P.includes(t),this.canBeFiltered&&(this.dict=B.get(t)),void 0!==s)if(Array.isArray(s))this.parse=this.enabled=!0,this.canBeFiltered&&s.length>0&&this.translateTagSet(s,this.pick);else if("object"==typeof s){if(this.enabled=!0,this.parse=!1!==s.parse,this.canBeFiltered){let{pick:e,skip:t}=s;e&&e.length>0&&this.translateTagSet(e,this.pick),t&&t.length>0&&this.translateTagSet(t,this.skip)}this.applyInheritables(s)}else!0===s||!1===s?this.parse=this.enabled=s:f(`Invalid options argument: ${s}`)}applyInheritables(e){let t,i;for(t of E)i=e[t],void 0!==i&&(this[t]=i)}translateTagSet(e,t){if(this.dict){let i,s,{tagKeys:n,tagValues:r}=this.dict;for(i of e)"string"==typeof i?(s=r.indexOf(i),-1===s&&(s=n.indexOf(Number(i))),-1!==s&&t.add(Number(n[s]))):t.add(i)}else for(let i of e)t.add(i)}finalizeFilters(){!this.enabled&&this.deps.size>0?(this.enabled=!0,X(this.pick,this.deps)):this.enabled&&this.pick.size>0&&X(this.pick,this.deps)}}var N={jfif:!1,tiff:!0,xmp:!1,icc:!1,iptc:!1,ifd0:!0,ifd1:!1,exif:!0,gps:!0,interop:!1,ihdr:void 0,makerNote:!1,userComment:!1,multiSegment:!1,skip:[],pick:[],translateKeys:!0,translateValues:!0,reviveValues:!0,sanitize:!0,mergeOutput:!0,silentErrors:!0,chunked:!0,firstChunkSize:void 0,firstChunkSizeNode:512,firstChunkSizeBrowser:65536,chunkSize:65536,chunkLimit:5},$=new Map;class R extends _{static useCached(e){let t=$.get(e);return void 0!==t||(t=new this(e),$.set(e,t)),t}constructor(e){super(),!0===e?this.setupFromTrue():void 0===e?this.setupFromUndefined():Array.isArray(e)?this.setupFromArray(e):"object"==typeof e?this.setupFromObject(e):f(`Invalid options argument ${e}`),void 0===this.firstChunkSize&&(this.firstChunkSize=i?this.firstChunkSizeBrowser:this.firstChunkSizeNode),this.mergeOutput&&(this.ifd1.enabled=!1),this.filterNestedSegmentTags(),this.traverseTiffDependencyTree(),this.checkLoadedPlugins()}setupFromUndefined(){let e;for(e of L)this[e]=N[e];for(e of M)this[e]=N[e];for(e of j)this[e]=N[e];for(e of F)this[e]=new D(e,N[e],void 0,this)}setupFromTrue(){let e;for(e of L)this[e]=N[e];for(e of M)this[e]=N[e];for(e of j)this[e]=!0;for(e of F)this[e]=new D(e,!0,void 0,this)}setupFromArray(e){let t;for(t of L)this[t]=N[t];for(t of M)this[t]=N[t];for(t of j)this[t]=N[t];for(t of F)this[t]=new D(t,!1,void 0,this);this.setupGlobalFilters(e,void 0,P)}setupFromObject(e){let t;for(t of(P.ifd0=P.ifd0||P.image,P.ifd1=P.ifd1||P.thumbnail,Object.assign(this,e),L))this[t]=W(e[t],N[t]);for(t of M)this[t]=W(e[t],N[t]);for(t of j)this[t]=W(e[t],N[t]);for(t of z)this[t]=new D(t,N[t],e[t],this);for(t of P)this[t]=new D(t,N[t],e[t],this.tiff);this.setupGlobalFilters(e.pick,e.skip,P,F),!0===e.tiff?this.batchEnableWithBool(P,!0):!1===e.tiff?this.batchEnableWithUserValue(P,e):Array.isArray(e.tiff)?this.setupGlobalFilters(e.tiff,void 0,P):"object"==typeof e.tiff&&this.setupGlobalFilters(e.tiff.pick,e.tiff.skip,P)}batchEnableWithBool(e,t){for(let i of e)this[i].enabled=t}batchEnableWithUserValue(e,t){for(let i of e){let e=t[i];this[i].enabled=!1!==e&&void 0!==e}}setupGlobalFilters(e,t,i){let s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:i;if(e&&e.length){for(let e of s)this[e].enabled=!1;let t=K(e,i);for(let[e,i]of t)X(this[e].pick,i),this[e].enabled=!0}else if(t&&t.length){let e=K(t,i);for(let[t,i]of e)X(this[t].skip,i)}}filterNestedSegmentTags(){let{ifd0:e,exif:t,xmp:i,iptc:s,icc:n}=this;this.makerNote?t.deps.add(37500):t.skip.add(37500),this.userComment?t.deps.add(37510):t.skip.add(37510),i.enabled||e.skip.add(700),s.enabled||e.skip.add(33723),n.enabled||e.skip.add(34675)}traverseTiffDependencyTree(){let{ifd0:e,exif:t,gps:i,interop:s}=this;s.needed&&(t.deps.add(40965),e.deps.add(40965)),t.needed&&e.deps.add(34665),i.needed&&e.deps.add(34853),this.tiff.enabled=P.some((e=>!0===this[e].enabled))||this.makerNote||this.userComment;for(let e of P)this[e].finalizeFilters()}get onlyTiff(){return!T.map((e=>this[e].enabled)).some((e=>!0===e))&&this.tiff.enabled}checkLoadedPlugins(){for(let e of z)this[e].enabled&&!y.has(e)&&g("segment parser",e)}}function K(e,t){let i,s,n,r,a=[];for(n of t){for(r of(i=B.get(n),s=[],i))(e.includes(r[0])||e.includes(r[1]))&&s.push(r[0]);s.length&&a.push([n,s])}return a}function W(e,t){return void 0!==e?e:void 0!==t?t:void 0}function X(e,t){for(let i of t)e.add(i)}e(R,"default",N);class H{constructor(t){e(this,"parsers",{}),e(this,"output",{}),e(this,"errors",[]),e(this,"pushToErrors",(e=>this.errors.push(e))),this.options=R.useCached(t)}async read(e){this.file=await function(e,t){return"string"==typeof e?k(e,t):i&&!s&&e instanceof HTMLImageElement?k(e.src,t):e instanceof Uint8Array||e instanceof ArrayBuffer||e instanceof DataView?new c(e):i&&e instanceof Blob?v(e,t,"blob",A):void f("Invalid input argument")}(e,this.options)}setup(){if(this.fileParser)return;let{file:e}=this,t=e.getUint16(0);for(let[i,s]of m)if(s.canHandle(e,t))return this.fileParser=new s(this.options,this.file,this.parsers),e[i]=!0;this.file.close&&this.file.close(),f("Unknown file format")}async parse(){let{output:e,errors:t}=this;return this.setup(),this.options.silentErrors?(await this.executeParsers().catch(this.pushToErrors),t.push(...this.fileParser.errors)):await this.executeParsers(),this.file.close&&this.file.close(),this.options.silentErrors&&t.length>0&&(e.errors=t),l(i=e)?void 0:i;var i}async executeParsers(){let{output:e}=this;await this.fileParser.parse();let t=Object.values(this.parsers).map((async t=>{let i=await t.parse();t.assignToOutput(e,i)}));this.options.silentErrors&&(t=t.map((e=>e.catch(this.pushToErrors)))),await Promise.all(t)}async extractThumbnail(){this.setup();let{options:e,file:t}=this,i=y.get("tiff",e);var s;if(t.tiff?s={start:0,type:"tiff"}:t.jpeg&&(s=await this.fileParser.getOrFindSegment("tiff")),void 0===s)return;let n=await this.fileParser.ensureSegmentChunk(s),r=this.parsers.tiff=new i(n,e,t),a=await r.extractThumbnail();return t.close&&t.close(),a}}async function Y(e,t){let i=new H(t);return await i.read(e),i.parse()}var G=Object.freeze({__proto__:null,parse:Y,Exifr:H,fileParsers:m,segmentParsers:y,fileReaders:b,tagKeys:B,tagValues:V,tagRevivers:I,createDictionary:x,extendDictionary:C,fetchUrlAsArrayBuffer:S,readBlobAsArrayBuffer:A,chunkedProps:L,otherSegments:T,segments:z,tiffBlocks:P,segmentsAndBlocks:F,tiffExtractables:j,inheritables:E,allFormatters:M,Options:R});class J{constructor(t,i,s){e(this,"errors",[]),e(this,"ensureSegmentChunk",(async e=>{let t=e.start,i=e.size||65536;if(this.file.chunked)if(this.file.available(t,i))e.chunk=this.file.subarray(t,i);else try{e.chunk=await this.file.readChunk(t,i)}catch(t){f(`Couldn't read segment: ${JSON.stringify(e)}. ${t.message}`)}else this.file.byteLength>t+i?e.chunk=this.file.subarray(t,i):void 0===e.size?e.chunk=this.file.subarray(t):f("Segment unreachable: "+JSON.stringify(e));return e.chunk})),this.extendOptions&&this.extendOptions(t),this.options=t,this.file=i,this.parsers=s}injectSegment(e,t){this.options[e].enabled&&this.createParser(e,t)}createParser(e,t){let i=new(y.get(e))(t,this.options,this.file);return this.parsers[e]=i}createParsers(e){for(let t of e){let{type:e,chunk:i}=t,s=this.options[e];if(s&&s.enabled){let t=this.parsers[e];t&&t.append||t||this.createParser(e,i)}}}async readSegments(e){let t=e.map(this.ensureSegmentChunk);await Promise.all(t)}}class q{static findPosition(e,t){let i=e.getUint16(t+2)+2,s="function"==typeof this.headerLength?this.headerLength(e,t,i):this.headerLength,n=t+s,r=i-s;return{offset:t,length:i,headerLength:s,start:n,size:r,end:n+r}}static parse(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return new this(e,new R({[this.type]:t}),e).parse()}normalizeInput(e){return e instanceof c?e:new c(e)}constructor(t){let i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},s=arguments.length>2?arguments[2]:void 0;e(this,"errors",[]),e(this,"raw",new Map),e(this,"handleError",(e=>{if(!this.options.silentErrors)throw e;this.errors.push(e.message)})),this.chunk=this.normalizeInput(t),this.file=s,this.type=this.constructor.type,this.globalOptions=this.options=i,this.localOptions=i[this.type],this.canTranslate=this.localOptions&&this.localOptions.translate}translate(){this.canTranslate&&(this.translated=this.translateBlock(this.raw,this.type))}get output(){return this.translated?this.translated:this.raw?Object.fromEntries(this.raw):void 0}translateBlock(e,t){let i=I.get(t),s=V.get(t),n=B.get(t),r=this.options[t],a=r.reviveValues&&!!i,h=r.translateValues&&!!s,l=r.translateKeys&&!!n,f={};for(let[t,r]of e)a&&i.has(t)?r=i.get(t)(r):h&&s.has(t)&&(r=this.translateValue(r,s.get(t))),l&&n.has(t)&&(t=n.get(t)||t),f[t]=r;return f}translateValue(e,t){return t[e]||t.DEFAULT||e}assignToOutput(e,t){this.assignObjectToOutput(e,this.constructor.type,t)}assignObjectToOutput(e,t,i){if(this.globalOptions.mergeOutput)return Object.assign(e,i);e[t]?Object.assign(e[t],i):e[t]=i}}e(q,"headerLength",4),e(q,"type",void 0),e(q,"multiSegment",!1),e(q,"canHandle",(()=>!1));function Q(e){return 192===e||194===e||196===e||219===e||221===e||218===e||254===e}function Z(e){return e>=224&&e<=239}function ee(e,t,i){for(let[s,n]of y)if(n.canHandle(e,t,i))return s}class te extends J{constructor(){super(...arguments),e(this,"appSegments",[]),e(this,"jpegSegments",[]),e(this,"unknownSegments",[])}static canHandle(e,t){return 65496===t}async parse(){await this.findAppSegments(),await this.readSegments(this.appSegments),this.mergeMultiSegments(),this.createParsers(this.mergedAppSegments||this.appSegments)}setupSegmentFinderArgs(e){!0===e?(this.findAll=!0,this.wanted=new Set(y.keyList())):(e=void 0===e?y.keyList().filter((e=>this.options[e].enabled)):e.filter((e=>this.options[e].enabled&&y.has(e))),this.findAll=!1,this.remaining=new Set(e),this.wanted=new Set(e)),this.unfinishedMultiSegment=!1}async findAppSegments(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1?arguments[1]:void 0;this.setupSegmentFinderArgs(t);let{file:i,findAll:s,wanted:n,remaining:r}=this;if(!s&&this.file.chunked&&(s=Array.from(n).some((e=>{let t=y.get(e),i=this.options[e];return t.multiSegment&&i.multiSegment})),s&&await this.file.readWhole()),e=this.findAppSegmentsInRange(e,i.byteLength),!this.options.onlyTiff&&i.chunked){let t=!1;for(;r.size>0&&!t&&(i.canReadNextChunk||this.unfinishedMultiSegment);){let{nextChunkOffset:s}=i,n=this.appSegments.some((e=>!this.file.available(e.offset||e.start,e.length||e.size)));if(t=e>s&&!n?!await i.readNextChunk(e):!await i.readNextChunk(s),e=this.findAppSegmentsInRange(e,i.byteLength),void 0===e)return}}}findAppSegmentsInRange(e,t){t-=2;let i,s,n,r,a,h,{file:l,findAll:f,wanted:o,remaining:u,options:d}=this;for(;e<t;e++)if(255===l.getUint8(e))if(i=l.getUint8(e+1),Z(i)){if(s=l.getUint16(e+2),n=ee(l,e,s),n&&o.has(n)&&(r=y.get(n),a=r.findPosition(l,e),h=d[n],a.type=n,this.appSegments.push(a),!f&&(r.multiSegment&&h.multiSegment?(this.unfinishedMultiSegment=a.chunkNumber<a.chunkCount,this.unfinishedMultiSegment||u.delete(n)):u.delete(n),0===u.size)))break;d.recordUnknownSegments&&(a=q.findPosition(l,e),a.marker=i,this.unknownSegments.push(a)),e+=s+1}else if(Q(i)){if(s=l.getUint16(e+2),218===i&&!1!==d.stopAfterSos)return;d.recordJpegSegments&&this.jpegSegments.push({offset:e,length:s,marker:i}),e+=s+1}return e}mergeMultiSegments(){if(!this.appSegments.some((e=>e.multiSegment)))return;let e=function(e,t){let i,s,n,r=new Map;for(let a=0;a<e.length;a++)i=e[a],s=i[t],r.has(s)?n=r.get(s):r.set(s,n=[]),n.push(i);return Array.from(r)}(this.appSegments,"type");this.mergedAppSegments=e.map((e=>{let[t,i]=e,s=y.get(t,this.options);if(s.handleMultiSegments){return{type:t,chunk:s.handleMultiSegments(i)}}return i[0]}))}getSegment(e){return this.appSegments.find((t=>t.type===e))}async getOrFindSegment(e){let t=this.getSegment(e);return void 0===t&&(await this.findAppSegments(0,[e]),t=this.getSegment(e)),t}}e(te,"type","jpeg"),m.set("jpeg",te);const ie=[void 0,1,1,2,4,8,1,1,2,4,8,4,8,4];class se extends q{parseHeader(){var e=this.chunk.getUint16();18761===e?this.le=!0:19789===e&&(this.le=!1),this.chunk.le=this.le,this.headerParsed=!0}parseTags(e,t){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:new Map,{pick:s,skip:n}=this.options[t];s=new Set(s);let r=s.size>0,a=0===n.size,h=this.chunk.getUint16(e);e+=2;for(let l=0;l<h;l++){let h=this.chunk.getUint16(e);if(r){if(s.has(h)&&(i.set(h,this.parseTag(e,h,t)),s.delete(h),0===s.size))break}else!a&&n.has(h)||i.set(h,this.parseTag(e,h,t));e+=12}return i}parseTag(e,t,i){let{chunk:s}=this,n=s.getUint16(e+2),r=s.getUint32(e+4),a=ie[n];if(a*r<=4?e+=8:e=s.getUint32(e+8),(n<1||n>13)&&f(`Invalid TIFF value type. block: ${i.toUpperCase()}, tag: ${t.toString(16)}, type: ${n}, offset ${e}`),e>s.byteLength&&f(`Invalid TIFF value offset. block: ${i.toUpperCase()}, tag: ${t.toString(16)}, type: ${n}, offset ${e} is outside of chunk size ${s.byteLength}`),1===n)return s.getUint8Array(e,r);if(2===n)return""===(h=function(e){for(;e.endsWith("\0");)e=e.slice(0,-1);return e}(h=s.getString(e,r)).trim())?void 0:h;var h;if(7===n)return s.getUint8Array(e,r);if(1===r)return this.parseTagValue(n,e);{let t=function(e){switch(e){case 1:return Uint8Array;case 3:return Uint16Array;case 4:return Uint32Array;case 5:case 10:default:return Array;case 6:return Int8Array;case 8:return Int16Array;case 9:return Int32Array;case 11:return Float32Array;case 12:return Float64Array}}(n),i=new t(r),s=a;for(let t=0;t<r;t++)i[t]=this.parseTagValue(n,e),e+=s;return i}}parseTagValue(e,t){let{chunk:i}=this;switch(e){case 1:return i.getUint8(t);case 3:return i.getUint16(t);case 4:case 13:return i.getUint32(t);case 5:return i.getUint32(t)/i.getUint32(t+4);case 6:return i.getInt8(t);case 8:return i.getInt16(t);case 9:return i.getInt32(t);case 10:return i.getInt32(t)/i.getInt32(t+4);case 11:return i.getFloat(t);case 12:return i.getDouble(t);default:f(`Invalid tiff type ${e}`)}}}class ne extends se{static canHandle(e,t){return 225===e.getUint8(t+1)&&1165519206===e.getUint32(t+4)&&0===e.getUint16(t+8)}async parse(){this.parseHeader();let{options:e}=this;return e.ifd0.enabled&&await this.parseIfd0Block(),e.exif.enabled&&await this.safeParse("parseExifBlock"),e.gps.enabled&&await this.safeParse("parseGpsBlock"),e.interop.enabled&&await this.safeParse("parseInteropBlock"),e.ifd1.enabled&&await this.safeParse("parseThumbnailBlock"),this.createOutput()}safeParse(e){let t=this[e]();return void 0!==t.catch&&(t=t.catch(this.handleError)),t}findIfd0Offset(){void 0===this.ifd0Offset&&(this.ifd0Offset=this.chunk.getUint32(4))}findIfd1Offset(){if(void 0===this.ifd1Offset){this.findIfd0Offset();let e=this.chunk.getUint16(this.ifd0Offset),t=this.ifd0Offset+2+12*e;this.ifd1Offset=this.chunk.getUint32(t)}}parseBlock(e,t){let i=new Map;return this[t]=i,this.parseTags(e,t,i),i}async parseIfd0Block(){if(this.ifd0)return;let{file:e}=this;this.findIfd0Offset(),this.ifd0Offset<8&&f("Malformed EXIF data"),!e.chunked&&this.ifd0Offset>e.byteLength&&f(`IFD0 offset points to outside of file.\nthis.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e.byteLength}`),e.tiff&&await e.ensureChunk(this.ifd0Offset,o(this.options));let t=this.parseBlock(this.ifd0Offset,"ifd0");return 0!==t.size?(this.exifOffset=t.get(34665),this.interopOffset=t.get(40965),this.gpsOffset=t.get(34853),this.xmp=t.get(700),this.iptc=t.get(33723),this.icc=t.get(34675),this.options.sanitize&&(t.delete(34665),t.delete(40965),t.delete(34853),t.delete(700),t.delete(33723),t.delete(34675)),t):void 0}async parseExifBlock(){if(this.exif)return;if(this.ifd0||await this.parseIfd0Block(),void 0===this.exifOffset)return;this.file.tiff&&await this.file.ensureChunk(this.exifOffset,o(this.options));let e=this.parseBlock(this.exifOffset,"exif");return this.interopOffset||(this.interopOffset=e.get(40965)),this.makerNote=e.get(37500),this.userComment=e.get(37510),this.options.sanitize&&(e.delete(40965),e.delete(37500),e.delete(37510)),this.unpack(e,41728),this.unpack(e,41729),e}unpack(e,t){let i=e.get(t);i&&1===i.length&&e.set(t,i[0])}async parseGpsBlock(){if(this.gps)return;if(this.ifd0||await this.parseIfd0Block(),void 0===this.gpsOffset)return;let e=this.parseBlock(this.gpsOffset,"gps");return e&&e.has(2)&&e.has(4)&&(e.set("latitude",re(...e.get(2),e.get(1))),e.set("longitude",re(...e.get(4),e.get(3)))),e}async parseInteropBlock(){if(!this.interop&&(this.ifd0||await this.parseIfd0Block(),void 0!==this.interopOffset||this.exif||await this.parseExifBlock(),void 0!==this.interopOffset))return this.parseBlock(this.interopOffset,"interop")}async parseThumbnailBlock(){let e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];if(!this.ifd1&&!this.ifd1Parsed&&(!this.options.mergeOutput||e))return this.findIfd1Offset(),this.ifd1Offset>0&&(this.parseBlock(this.ifd1Offset,"ifd1"),this.ifd1Parsed=!0),this.ifd1}async extractThumbnail(){if(this.headerParsed||this.parseHeader(),this.ifd1Parsed||await this.parseThumbnailBlock(!0),void 0===this.ifd1)return;let e=this.ifd1.get(513),t=this.ifd1.get(514);return this.chunk.getUint8Array(e,t)}get image(){return this.ifd0}get thumbnail(){return this.ifd1}createOutput(){let e,t,i,s={};for(t of P)if(e=this[t],!l(e))if(i=this.canTranslate?this.translateBlock(e,t):Object.fromEntries(e),this.options.mergeOutput){if("ifd1"===t)continue;Object.assign(s,i)}else s[t]=i;return this.makerNote&&(s.makerNote=this.makerNote),this.userComment&&(s.userComment=this.userComment),s}assignToOutput(e,t){if(this.globalOptions.mergeOutput)Object.assign(e,t);else for(let[i,s]of Object.entries(t))this.assignObjectToOutput(e,i,s)}}function re(e,t,i,s){var n=e+t/60+i/3600;return"S"!==s&&"W"!==s||(n*=-1),n}e(ne,"type","tiff"),e(ne,"headerLength",10),y.set("tiff",ne);var ae=Object.freeze({__proto__:null,default:G,Exifr:H,fileParsers:m,segmentParsers:y,fileReaders:b,tagKeys:B,tagValues:V,tagRevivers:I,createDictionary:x,extendDictionary:C,fetchUrlAsArrayBuffer:S,readBlobAsArrayBuffer:A,chunkedProps:L,otherSegments:T,segments:z,tiffBlocks:P,segmentsAndBlocks:F,tiffExtractables:j,inheritables:E,allFormatters:M,Options:R,parse:Y});const he={ifd0:!1,ifd1:!1,exif:!1,gps:!1,interop:!1,sanitize:!1,reviveValues:!0,translateKeys:!1,translateValues:!1,mergeOutput:!1},le=Object.assign({},he,{firstChunkSize:4e4,gps:[1,2,3,4]});async function fe(e){let t=new H(le);await t.read(e);let i=await t.parse();if(i&&i.gps){let{latitude:e,longitude:t}=i.gps;return{latitude:e,longitude:t}}}const oe=Object.assign({},he,{tiff:!1,ifd1:!0,mergeOutput:!1});async function ue(e){let t=new H(oe);await t.read(e);let i=await t.extractThumbnail();return i&&a?r.from(i):i}async function de(e){let t=await this.thumbnail(e);if(void 0!==t){let e=new Blob([t]);return URL.createObjectURL(e)}}const ce=Object.assign({},he,{firstChunkSize:4e4,ifd0:[274]});async function ge(e){let t=new H(ce);await t.read(e);let i=await t.parse();if(i&&i.ifd0)return i.ifd0[274]}const pe=Object.freeze({1:{dimensionSwapped:!1,scaleX:1,scaleY:1,deg:0,rad:0},2:{dimensionSwapped:!1,scaleX:-1,scaleY:1,deg:0,rad:0},3:{dimensionSwapped:!1,scaleX:1,scaleY:1,deg:180,rad:180*Math.PI/180},4:{dimensionSwapped:!1,scaleX:-1,scaleY:1,deg:180,rad:180*Math.PI/180},5:{dimensionSwapped:!0,scaleX:1,scaleY:-1,deg:90,rad:90*Math.PI/180},6:{dimensionSwapped:!0,scaleX:1,scaleY:1,deg:90,rad:90*Math.PI/180},7:{dimensionSwapped:!0,scaleX:1,scaleY:-1,deg:270,rad:270*Math.PI/180},8:{dimensionSwapped:!0,scaleX:1,scaleY:1,deg:270,rad:270*Math.PI/180}});let me=!0,ye=!0;if("object"==typeof navigator){let e=navigator.userAgent;if(e.includes("iPad")||e.includes("iPhone")){let t=e.match(/OS (\d+)_(\d+)/);if(t){let[,e,i]=t,s=Number(e)+.1*Number(i);me=s<13.4,ye=!1}}else if(e.includes("OS X 10")){let[,t]=e.match(/OS X 10[_.](\d+)/);me=ye=Number(t)<15}if(e.includes("Chrome/")){let[,t]=e.match(/Chrome\/(\d+)/);me=ye=Number(t)<81}else if(e.includes("Firefox/")){let[,t]=e.match(/Firefox\/(\d+)/);me=ye=Number(t)<77}}async function be(e){let t=await ge(e);return Object.assign({canvas:me,css:ye},pe[t])}class we extends c{constructor(){super(...arguments),e(this,"ranges",new ke),0!==this.byteLength&&this.ranges.add(0,this.byteLength)}_tryExtend(e,t,i){if(0===e&&0===this.byteLength&&i){let e=new DataView(i.buffer||i,i.byteOffset,i.byteLength);this._swapDataView(e)}else{let i=e+t;if(i>this.byteLength){let{dataView:e}=this._extend(i);this._swapDataView(e)}}}_extend(e){let t;t=a?r.allocUnsafe(e):new Uint8Array(e);let i=new DataView(t.buffer,t.byteOffset,t.byteLength);return t.set(new Uint8Array(this.buffer,this.byteOffset,this.byteLength),0),{uintView:t,dataView:i}}subarray(e,t){let i=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return t=t||this._lengthToEnd(e),i&&this._tryExtend(e,t),this.ranges.add(e,t),super.subarray(e,t)}set(e,t){arguments.length>2&&void 0!==arguments[2]&&arguments[2]&&this._tryExtend(t,e.byteLength,e);let i=super.set(e,t);return this.ranges.add(t,i.byteLength),i}async ensureChunk(e,t){this.chunked&&(this.ranges.available(e,t)||await this.readChunk(e,t))}available(e,t){return this.ranges.available(e,t)}}class ke{constructor(){e(this,"list",[])}get length(){return this.list.length}add(e,t){let i=e+t,s=this.list.filter((t=>ve(e,t.offset,i)||ve(e,t.end,i)));if(s.length>0){e=Math.min(e,...s.map((e=>e.offset))),i=Math.max(i,...s.map((e=>e.end))),t=i-e;let n=s.shift();n.offset=e,n.length=t,n.end=i,this.list=this.list.filter((e=>!s.includes(e)))}else this.list.push({offset:e,length:t,end:i})}available(e,t){let i=e+t;return this.list.some((t=>t.offset<=e&&i<=t.end))}}function ve(e,t,i){return e<=t&&t<=i}class Oe extends we{constructor(t,i){super(0),e(this,"chunksRead",0),this.input=t,this.options=i}async readWhole(){this.chunked=!1,await this.readChunk(this.nextChunkOffset)}async readChunked(){this.chunked=!0,await this.readChunk(0,this.options.firstChunkSize)}async readNextChunk(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.nextChunkOffset;if(this.fullyRead)return this.chunksRead++,!1;let t=this.options.chunkSize,i=await this.readChunk(e,t);return!!i&&i.byteLength===t}async readChunk(e,t){if(this.chunksRead++,0!==(t=this.safeWrapAddress(e,t)))return this._readChunk(e,t)}safeWrapAddress(e,t){return void 0!==this.size&&e+t>this.size?Math.max(0,this.size-e):t}get nextChunkOffset(){if(0!==this.ranges.list.length)return this.ranges.list[0].length}get canReadNextChunk(){return this.chunksRead<this.options.chunkLimit}get fullyRead(){return void 0!==this.size&&this.nextChunkOffset===this.size}read(){return this.options.chunked?this.readChunked():this.readWhole()}close(){}}b.set("blob",class extends Oe{async readWhole(){this.chunked=!1;let e=await A(this.input);this._swapArrayBuffer(e)}readChunked(){return this.chunked=!0,this.size=this.input.size,super.readChunked()}async _readChunk(e,t){let i=t?e+t:void 0,s=this.input.slice(e,i),n=await A(s);return this.set(n,e,!0)}});export{H as Exifr,R as Options,M as allFormatters,L as chunkedProps,x as createDictionary,ae as default,C as extendDictionary,S as fetchUrlAsArrayBuffer,m as fileParsers,b as fileReaders,fe as gps,le as gpsOnlyOptions,E as inheritables,ge as orientation,ce as orientationOnlyOptions,T as otherSegments,Y as parse,A as readBlobAsArrayBuffer,me as rotateCanvas,ye as rotateCss,be as rotation,pe as rotations,y as segmentParsers,z as segments,F as segmentsAndBlocks,B as tagKeys,I as tagRevivers,V as tagValues,ue as thumbnail,oe as thumbnailOnlyOptions,de as thumbnailUrl,P as tiffBlocks,j as tiffExtractables};