dynamsoft-utility
Version:
The Dynamsoft Utility module defines auxiliary classes shared by all Dynamsoft SDKs compliant with the Dynamsoft Capture Vision architecture.
12 lines (11 loc) • 17 kB
JavaScript
/*!
* Dynamsoft JavaScript Library
* @product Dynamsoft Utility JS Edition
* @website https://www.dynamsoft.com
* @copyright Copyright 2024, Dynamsoft Corporation
* @author Dynamsoft
* @version 1.4.32
* @fileoverview Dynamsoft JavaScript Library for Utility
* More info DU JS: https://www.dynamsoft.com/capture-vision/docs/web/programming/javascript/api-reference/utility/utility-module.html
*/
import{_getNorImageData as t,_saveToFile as e,requestResource as i,getNextTaskID as n,mapTaskCallBack as o,worker as s,CoreModule as a,workerAutoResources as r,compareVersion as l,innerVersions as c,EnumCapturedResultItemType as h}from"dynamsoft-core";const f=async t=>{let e;await new Promise(((i,n)=>{e=new Image,e.onload=()=>i(e),e.onerror=n,e.src=URL.createObjectURL(t)}));const i=document.createElement("canvas"),n=i.getContext("2d");i.width=e.width,i.height=e.height,n.drawImage(e,0,0);return{bytes:Uint8Array.from(n.getImageData(0,0,i.width,i.height).data),width:i.width,height:i.height,stride:4*i.width,format:10}};class p{async saveToFile(i,n,o){if(!i||!n)return null;if("string"!=typeof n)throw new TypeError("FileName must be of type string.");const s=t(i);return e(s,n,o)}async drawOnImage(t,e,a,r=4294901760,l=1,c){let h;if(t instanceof Blob)h=await f(t);else if("string"==typeof t){let e=await i(t,"blob");h=await f(e)}return await new Promise(((t,i)=>{let f=n();o[f]=async e=>{if(e.success)return c&&this.saveToFile(e.image,"test.png",c),t(e.image);{let t=new Error(e.message);return t.stack=e.stack+"\n"+t.stack,i(t)}},s.postMessage({type:"utility_drawOnImage",id:f,body:{dsImage:h,drawingItem:e instanceof Array?e:[e],color:r,thickness:l,type:a}})}))}}const u="undefined"==typeof self,g="function"==typeof importScripts,d=(()=>{if(!g){if(!u&&document.currentScript){let t=document.currentScript.src,e=t.indexOf("?");if(-1!=e)t=t.substring(0,e);else{let e=t.indexOf("#");-1!=e&&(t=t.substring(0,e))}return t.substring(0,t.lastIndexOf("/")+1)}return"./"}})(),y=t=>{if(null==t&&(t="./"),u||g);else{let e=document.createElement("a");e.href=t,t=e.href}return t.endsWith("/")||(t+="/"),t};a.engineResourcePaths.utility={version:"1.4.32",path:d,isInternal:!0},r.utility={js:!0,wasm:!0};const m="1.4.21";"string"!=typeof a.engineResourcePaths.std&&l(a.engineResourcePaths.std.version,m)<0&&(a.engineResourcePaths.std={version:m,path:y(d+`../../dynamsoft-capture-vision-std@${m}/dist/`),isInternal:!0});const v="2.4.31";(!a.engineResourcePaths.dip||"string"!=typeof a.engineResourcePaths.dip&&l(a.engineResourcePaths.dip.version,v)<0)&&(a.engineResourcePaths.dip={version:v,path:y(d+`../../dynamsoft-image-processing@${v}/dist/`),isInternal:!0});class x{static getVersion(){return`1.4.32(Worker: ${c.utility&&c.utility.worker||"Not Loaded"}, Wasm: ${c.utility&&c.utility.wasm||"Not Loaded"})`}}function I(t,e,i,n){if("a"===i&&!n)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===i?n:"a"===i?n.call(t):n?n.value:e.get(t)}var E,b,R,T,_;function C(t,e){let i=!0;for(let a=0;a<t.length;a++){const r=(a+1)%t.length;if((n=t[a],o=t[r],s=e,(o.x-n.x)*(s.y-n.y)-(o.y-n.y)*(s.x-n.x))<0){i=!1;break}}var n,o,s;return i}function O(t,e){return Math.sqrt((t.x-e.x)**2+(t.y-e.y)**2)}function B(t,e){const[i,n]=t,o=i.x,s=i.y,a=n.x,r=n.y,l=e.x,c=e.y,h=(a-o)**2+(r-s)**2;if(0===h)return Math.sqrt((l-o)**2+(c-s)**2);const f=((l-o)*(a-o)+(c-s)*(r-s))/h;if(f<0)return Math.sqrt((l-o)**2+(c-s)**2);if(f>1)return Math.sqrt((l-a)**2+(c-r)**2);{const t=o+f*(a-o),e=s+f*(r-s);return Math.sqrt((l-t)**2+(c-e)**2)}}function M(t){const e=[];for(let i=0;i<t.length;i++){const n=t[i],o=t[(i+1)%t.length];e.push([n,o])}return e}function A(t){const[e,i]=t;return{x:(e.x+i.x)/2,y:(e.y+i.y)/2}}function D(t,e){const i=[];for(let n=0;n<4;n++)for(let o=0;o<4;o++){const s=S(t[n],t[(n+1)%4],e[o],e[(o+1)%4]);s&&i.push(s)}t.forEach((t=>{C(e,t)&&i.push(t)})),e.forEach((e=>{C(t,e)&&i.push(e)}));return w(function(t){if(t.length<=1)return t;t.sort(((t,e)=>t.x-e.x||t.y-e.y));const e=t.shift();return t.sort(((t,i)=>Math.atan2(t.y-e.y,t.x-e.x)-Math.atan2(i.y-e.y,i.x-e.x))),[e,...t]}(i))}function S(t,e,i,n){const o=e.x-t.x,s=e.y-t.y,a=n.x-i.x,r=n.y-i.y,l=(-s*(t.x-i.x)+o*(t.y-i.y))/(-a*s+o*r),c=(a*(t.y-i.y)-r*(t.x-i.x))/(-a*s+o*r);return l>=0&&l<=1&&c>=0&&c<=1?{x:t.x+c*o,y:t.y+c*s}:null}function w(t){let e=0;for(let i=0;i<t.length;i++){const n=(i+1)%t.length;e+=t[i].x*t[n].y,e-=t[n].x*t[i].y}return Math.abs(e/2)}function F(t,e,i){let n=e.x-t.x,o=e.y-t.y,s=i.x-t.x;return n*(i.y-t.y)-o*s>0}function L(t,e){for(let i=0;i<4;i++)if(!F(t.points[i],t.points[(i+1)%4],e))return!1;return!0}"function"==typeof SuppressedError&&SuppressedError;const N=3,k=1,P=1,W=2,G=3,j=5,V=15,U=5;function Q(t,e,i,n){const o=t.points,s=e.points;let a=8*i;a=Math.max(a,5);const r=M(o)[3],l=M(o)[1],c=M(s)[3],h=M(s)[1];let f,p=0;if(f=Math.max(Math.abs(B(r,e.points[0])),Math.abs(B(r,e.points[3]))),f>p&&(p=f),f=Math.max(Math.abs(B(l,e.points[1])),Math.abs(B(l,e.points[2]))),f>p&&(p=f),f=Math.max(Math.abs(B(c,t.points[0])),Math.abs(B(c,t.points[3]))),f>p&&(p=f),f=Math.max(Math.abs(B(h,t.points[1])),Math.abs(B(h,t.points[2]))),f>p&&(p=f),p>a)return!1;const u=A(M(o)[0]),g=A(M(o)[2]),d=A(M(s)[0]),y=A(M(s)[2]),m=O(u,y),v=O(d,g),x=m>v,I=Math.min(m,v),E=O(u,g),b=O(d,y);let R=12*i;R=Math.max(R,5),R=Math.min(R,E),R=Math.min(R,b);return!!(I<R||C(o,x?d:y)||C(s,x?g:u))&&(x?(n.points[0]=t.points[0],n.points[1]=t.points[1],n.points[2]=e.points[2],n.points[3]=e.points[3]):(n.points[0]=e.points[0],n.points[1]=e.points[1],n.points[2]=t.points[2],n.points[3]=t.points[3]),n.area=w(n.points),!0)}class X{constructor(t,e,i,n){this.overlapCount=t,this.verificationCount=e,this.crossVerificationFrame=5,this.location=n.location,this.locationArea=n.location.area,this.locationAngle=n.angle,this.format=n.format,this.text=n.text,this.isOneD=i,this.item=n;this.locationThreshold=n.moduleSize*j,this.strictLimit=Math.max(this.locationThreshold,1),this.strictLimit=Math.min(this.strictLimit,15)}getCenterPoint(t){const e={x:0,y:0};return t.forEach((({x:t,y:i})=>{e.x+=t,e.y+=i})),e.x/=t.length,e.y/=t.length,e}isProbablySameLocationWithOffset(t,e){const i=this.item.location,n=t.location;if(i.area<=0)return!1;if(Math.abs(i.area-n.area)>.4*i.area)return!1;let o=new Array(4).fill(0),s=new Array(4).fill(0),a=0,r=0;for(let t=0;t<4;++t)o[t]=Math.round(100*(n.points[t].x-i.points[t].x))/100,a+=o[t],s[t]=Math.round(100*(n.points[t].y-i.points[t].y))/100,r+=s[t];a/=4,r/=4;for(let t=0;t<4;++t){if(Math.abs(o[t]-a)>this.strictLimit||Math.abs(a)>.8)return!1;if(Math.abs(s[t]-r)>this.strictLimit||Math.abs(r)>.8)return!1}return e.x=a,e.y=r,!0}isLocationOverlap(t,e){if(this.locationArea>e){for(let e=0;e<4;e++)if(L(this.location,t.points[e]))return!0;const e=this.getCenterPoint(t.points);if(L(this.location,e))return!0}else{for(let e=0;e<4;e++)if(L(t,this.location.points[e]))return!0;if(L(t,this.getCenterPoint(this.location.points)))return!0}return!1}isMatchedLocationWithOffset(t,e={x:0,y:0}){if(this.isOneD){const i=Object.assign({},t.location);for(let t=0;t<4;t++)i.points[t].x-=e.x,i.points[t].y-=e.y;if(!this.isLocationOverlap(i,t.locationArea))return!1;const n=[this.location.points[0],this.location.points[3]],o=[this.location.points[1],this.location.points[2]];for(let t=0;t<4;t++){const e=i.points[t],s=0===t||3===t?n:o;if(Math.abs(B(s,e))>this.locationThreshold)return!1}}else for(let i=0;i<4;i++){const n=t.location.points[i],o=this.location.points[i];if(!(Math.abs(o.x+e.x-n.x)<this.locationThreshold))return!1;if(Math.abs(o.y+e.y-n.y)>=this.locationThreshold)return!1}return!0}isOverlappedLocationWithOffset(t,e,i=!0){const n=Object.assign({},t.location);for(let t=0;t<4;t++)n.points[t].x-=e.x,n.points[t].y-=e.y;if(!this.isLocationOverlap(n,t.location.area))return!1;if(i){const t=.75;return D([...this.location.points],n.points)>this.locationArea*t}return!0}}const Z={BF_ONED:BigInt(3147775),BF_GS1_DATABAR:BigInt(260096)},q={barcode:2,text_line:4,detected_quad:8,normalized_image:16},z=t=>Object.values(q).includes(t)||q.hasOwnProperty(t),$=(t,e)=>"string"==typeof t?e[q[t]]:e[t],H=(t,e,i)=>{"string"==typeof t?e[q[t]]=i:e[t]=i},J=(t,e,i)=>{const n=[8,16].includes(i);if(!n&&t.isResultCrossVerificationEnabled(i))for(let t=0;t<e.length;t++)e[t]&&e[t].type===i&&!e[t].verified&&(e[t].isFilter=!0);if(!n&&t.isResultDeduplicationEnabled(i))for(let t=0;t<e.length;t++)e[t]&&e[t].type===i&&e[t].duplicate&&(e[t].isFilter=!0)};class K{constructor(){this.verificationEnabled={[h.CRIT_BARCODE]:!1,[h.CRIT_TEXT_LINE]:!0,[h.CRIT_DETECTED_QUAD]:!0,[h.CRIT_NORMALIZED_IMAGE]:!1},this.duplicateFilterEnabled={[h.CRIT_BARCODE]:!1,[h.CRIT_TEXT_LINE]:!1,[h.CRIT_DETECTED_QUAD]:!1,[h.CRIT_NORMALIZED_IMAGE]:!1},this.duplicateForgetTime={[h.CRIT_BARCODE]:3e3,[h.CRIT_TEXT_LINE]:3e3,[h.CRIT_DETECTED_QUAD]:3e3,[h.CRIT_NORMALIZED_IMAGE]:3e3},this.latestOverlappingEnabled={[h.CRIT_BARCODE]:!1,[h.CRIT_TEXT_LINE]:!1,[h.CRIT_DETECTED_QUAD]:!1,[h.CRIT_NORMALIZED_IMAGE]:!1},this.maxOverlappingFrames={[h.CRIT_BARCODE]:5,[h.CRIT_TEXT_LINE]:5,[h.CRIT_DETECTED_QUAD]:5,[h.CRIT_NORMALIZED_IMAGE]:5},this.overlapSet=[],this.stabilityCount=0,this.crossVerificationFrames=5,E.set(this,new Map),b.set(this,new Map),R.set(this,new Map),T.set(this,new Map),_.set(this,new Map)}_dynamsoft(){I(this,E,"f").forEach(((t,e)=>{H(e,this.verificationEnabled,t)})),I(this,b,"f").forEach(((t,e)=>{H(e,this.duplicateFilterEnabled,t)})),I(this,R,"f").forEach(((t,e)=>{H(e,this.duplicateForgetTime,t)})),I(this,T,"f").forEach(((t,e)=>{H(e,this.latestOverlappingEnabled,t)})),I(this,_,"f").forEach(((t,e)=>{H(e,this.maxOverlappingFrames,t)}))}enableResultCrossVerification(t,e){z(t)&&I(this,E,"f").set(t,e)}isResultCrossVerificationEnabled(t){return!!z(t)&&$(t,this.verificationEnabled)}enableResultDeduplication(t,e){z(t)&&(e&&this.enableLatestOverlapping(t,!1),I(this,b,"f").set(t,e))}isResultDeduplicationEnabled(t){return!!z(t)&&$(t,this.duplicateFilterEnabled)}setDuplicateForgetTime(t,e){z(t)&&(e>18e4&&(e=18e4),e<0&&(e=0),I(this,R,"f").set(t,e))}getDuplicateForgetTime(t){return z(t)?$(t,this.duplicateForgetTime):-1}setMaxOverlappingFrames(t,e){z(t)&&I(this,_,"f").set(t,e)}getMaxOverlappingFrames(t){return z(t)?$(t,this.maxOverlappingFrames):-1}enableLatestOverlapping(t,e){z(t)&&(e&&this.enableResultDeduplication(t,!1),I(this,T,"f").set(t,e))}isLatestOverlappingEnabled(t){return!!z(t)&&$(t,this.latestOverlappingEnabled)}getFilteredResultItemTypes(){let t=0;const e=[h.CRIT_BARCODE,h.CRIT_TEXT_LINE,h.CRIT_DETECTED_QUAD,h.CRIT_NORMALIZED_IMAGE];for(let i=0;i<e.length;i++)(this.verificationEnabled[e[i]]||this.duplicateFilterEnabled[e[i]])&&(t|=e[i]);return t}onOriginalImageResultReceived(t){}latestOverlappingFilter(t){var e,i,n;const o=this.isResultCrossVerificationEnabled(h.CRIT_BARCODE),s=this.isLatestOverlappingEnabled(h.CRIT_BARCODE);if(s){const a=5,r=60,l=s?this.getMaxOverlappingFrames(h.CRIT_BARCODE):5,c=t.items.length,f=null===(n=null===(i=null===(e=null==t?void 0:t.intermediateResult)||void 0===e?void 0:e[0])||void 0===i?void 0:i.intermediateResultUnits)||void 0===n?void 0:n[1].localizedBarcodes,p=f?f.length:0;let u=[];const g=[],d={x:0,y:0};let y=new Array(c).fill(-1),m=0;const v=t.items.map((t=>{if(1!==t.type){const e=(BigInt(t.format)&BigInt(Z.BF_ONED))!=BigInt(0)||(BigInt(t.format)&BigInt(Z.BF_GS1_DATABAR))!=BigInt(0);return new X(l,e?1:2,e,t)}})).filter(Boolean);if(this.overlapSet.length>0){const t=new Array(c).fill(new Array(this.overlapSet.length).fill(1));let e=0;for(;e<c;){const i={x:0,y:0},n=new Array(c).fill(-1);let o=!1;for(;e<c;e++){if(!v[e])continue;const s=v[e].item;for(let a=0;a<this.overlapSet.length;a++){if(t[e][a]<1)continue;const r=this.overlapSet[a],l=r.item;if(s.format===l.format&&s.text===l.text){if(o=r.isProbablySameLocationWithOffset(v[e],i),o){n[e]=a,t[e][a]=0;break}}else t[e][a]=0}if(o)break}if(o){for(let o=0;o<c;o++){if(o===e||!v[o])continue;const s=v[o].item;for(let e=0;e<this.overlapSet.length;e++){if(t[o][e]<1)continue;if(n.includes(e))continue;const a=this.overlapSet[e],r=a.item;if(s.format===r.format&&s.text===r.text){if(a.isMatchedLocationWithOffset(v[o],i)){n[o]=e,t[o][e]=0;break}}else t[o][e]=0}}const o=n.filter((t=>-1!==t)).length;o>m&&(m=o,y=n,d.x=i.x,d.y=i.y)}}if(0===m){for(let e=0;e<c;e++){const i=v[e].item;for(let n=0;n<this.overlapSet.length;n++){if(t[e][n]<1)continue;if(y.includes(n))continue;const o=this.overlapSet[n],s=o.item;if(i.format===s.format&&i.text===s.text){if(o.isMatchedLocationWithOffset(v[e])){y[e]=n,t[e][n]=0;break}}else t[e][n]=0}}m+=y.filter((t=>-1!=t)).length}let i=this.overlapSet.length<=N?m>=k:m>=W;if(!i&&s&&p>0){let t=0;for(let e=0;e<this.overlapSet.length;e++){const i=this.overlapSet[e];for(let e=0;e<p;e++){if(i.isOverlappedLocationWithOffset(f[e],d)){t++;break}}}i=this.overlapSet.length<=N?t>=P:t>=G}i||(this.overlapSet=[])}if(0===this.overlapSet.length)this.stabilityCount=0,t.items.forEach(((t,e)=>{if(1!==t.type){const i=Object.assign({},t),n=(BigInt(t.format)&BigInt(Z.BF_ONED))!=BigInt(0)||(BigInt(t.format)&BigInt(Z.BF_GS1_DATABAR))!=BigInt(0),s=t.confidence<r,a=new X(l,n?1:2,n,i);o&&n&&s&&g.push(e),this.overlapSet.push(a)}}));else{let e=!0;s?(Math.abs(d.x)>U||Math.abs(d.y)>U)&&(e=!1):e=!1;for(let i=0;i<t.items.length;i++){const t=y[i];if(t<0&&v[i]){const t=v[i].item;let n={points:[{x:0,y:0},{x:0,y:0},{x:0,y:0},{x:0,y:0}],area:0};for(let i=0;i<4;i++)n.points[i].x=e?t.location.points[i].x-d.x:t.location.points[i].x,n.points[i].y=e?t.location.points[i].y-d.y:t.location.points[i].y;for(let o=0;o<this.overlapSet.length;o++){if(y.includes(o))continue;const s=this.overlapSet[o].item.text,a=this.overlapSet[o].item.format;if(t.format===a&&t.text===s){if(this.overlapSet[o].isOverlappedLocationWithOffset(t,d,!1)){const e=Object.assign({},t),n=(BigInt(e.format)&BigInt(Z.BF_ONED))!=BigInt(0)||(BigInt(e.format)&BigInt(Z.BF_GS1_DATABAR))!=BigInt(0),s=n?1:2;this.overlapSet[o]=new X(l,s,n,e),y[i]=o;break}if(v[i].isOneD){let s={points:[{x:0,y:0},{x:0,y:0},{x:0,y:0},{x:0,y:0}],area:0};for(let t=0;t<4;t++)s.points[t].x=e?this.overlapSet[o].location.points[t].x:this.overlapSet[o].location.points[t].x+d.x,s.points[t].y=e?this.overlapSet[o].location.points[t].y:this.overlapSet[o].location.points[t].y+d.y;let a={points:[{x:0,y:0},{x:0,y:0},{x:0,y:0},{x:0,y:0}],area:0};if(Q(n,s,t.moduleSize,a)){t.location=a;const e=Object.assign({},t),n=(BigInt(e.format)&BigInt(Z.BF_ONED))!=BigInt(0)||(BigInt(e.format)&BigInt(Z.BF_GS1_DATABAR))!=BigInt(0),s=n?1:2;this.overlapSet[o]=new X(l,s,n,e),y[i]=o;break}}}}}else{if(e){if(v[i]){v[i].item.location=this.overlapSet[t].location}}else{const e=Object.assign({},v[i].item),n=(BigInt(e.format)&BigInt(Z.BF_ONED))!=BigInt(0)||(BigInt(e.format)&BigInt(Z.BF_GS1_DATABAR))!=BigInt(0),o=n?1:2;this.overlapSet[t]=new X(l,o,n,e)}this.overlapSet[t]&&(this.overlapSet[t].overlapCount=l,this.overlapSet[t].verificationCount=2,this.overlapSet[t].crossVerificationFrame=a)}}e?this.stabilityCount<V&&this.stabilityCount++:this.stabilityCount=0;let i=!0;for(let t=0;t<this.overlapSet.length;t++){if(y.includes(t))continue;const n=this.overlapSet[t];n.overlapCount--,n.crossVerificationFrame--;const o=n.overlapCount+this.stabilityCount;if(s&&o>0){for(let t=0;t<c;t++){if(n.isOverlappedLocationWithOffset(v[t],d,!1)){i=!1;break}}if(!i)break;const t=n.item;if(!e){for(let t=0;t<4;t++)n.location.points[t].x+=d.x,n.location.points[t].y+=d.y;t.location=n.location}2===n.verificationCount&&u.push(t)}}if(s&&!i){u=[];for(let t=0;t<this.overlapSet.length;t++){if(y.includes(t))continue;const e=this.overlapSet[t];e.overlapCount=0-this.stabilityCount,e.crossVerificationFrame=0,e.verificationCount=0}}for(let t=0;t<c;t++){if(-1!==y[t]||!v[t])continue;const i=v[t].item;if(e){for(let e=0;e<4;e++)v[t].location.points[e].x-=d.x,v[t].location.points[e].y-=d.y;i.location=v[t].location}let n=!1;for(let e of this.overlapSet)if(!(e.crossVerificationFrame<=0&&e.verificationCount<=0)&&(n=e.isLocationOverlap(v[t].location,v[t].locationArea),n))break;if(n){g.push(t);continue}const s=Object.assign({},i),a=(BigInt(i.format)&BigInt(Z.BF_ONED))!=BigInt(0)||(BigInt(i.format)&BigInt(Z.BF_GS1_DATABAR))!=BigInt(0),c=i.confidence<r,h=new X(l,a?1:2,a,s);o&&a&&c?g.push(t):h.verificationCount=2,this.overlapSet.push(h)}this.overlapSet=this.overlapSet.filter((t=>!(t.overlapCount+this.stabilityCount<=0&&t.crossVerificationFrame<=0)))}g.sort(((t,e)=>e-t)).forEach(((e,i)=>{t.items.splice(e,1)})),u.forEach((e=>{t.items.push(Object.assign(Object.assign({},e),{overlapped:!0}))}))}}onDecodedBarcodesReceived(t){this.latestOverlappingFilter(t),J(this,t.items,h.CRIT_BARCODE)}onRecognizedTextLinesReceived(t){J(this,t.items,h.CRIT_TEXT_LINE)}onDetectedQuadsReceived(t){J(this,t.items,h.CRIT_DETECTED_QUAD)}onNormalizedImagesReceived(t){J(this,t.items,h.CRIT_NORMALIZED_IMAGE)}}E=new WeakMap,b=new WeakMap,R=new WeakMap,T=new WeakMap,_=new WeakMap;export{p as ImageManager,K as MultiFrameResultCrossFilter,x as UtilityModule};