Files
FreeERP.Applet/miniprogram/miniprogram_npm/tdesign-miniprogram/common/shared/qrcode/qrcodegen.js
2025-11-28 16:49:36 +08:00

1 line
12 KiB
JavaScript

function appendBits(t,e,r){if(e<0||e>31||t>>>e!==0)throw new RangeError("Value out of range");for(let o=e-1;o>=0;o--)r.push(t>>>o&1)}function getBit(t,e){return!!(t>>>e&1)}function assert(t){if(!t)throw new Error("Assertion error")}export class Mode{constructor(t,e){this.modeBits=t,this.numBitsCharCount=e}numCharCountBits(t){return this.numBitsCharCount[Math.floor((t+7)/17)]}}Mode.NUMERIC=new Mode(1,[10,12,14]),Mode.ALPHANUMERIC=new Mode(2,[9,11,13]),Mode.BYTE=new Mode(4,[8,16,16]),Mode.KANJI=new Mode(8,[8,10,12]),Mode.ECI=new Mode(7,[0,0,0]);export class Ecc{constructor(t,e){this.ordinal=t,this.formatBits=e}}Ecc.LOW=new Ecc(0,1),Ecc.MEDIUM=new Ecc(1,0),Ecc.QUARTILE=new Ecc(2,3),Ecc.HIGH=new Ecc(3,2);export class QrSegment{constructor(t,e,r){if(this.mode=t,this.numChars=e,this.bitData=r,e<0)throw new RangeError("Invalid argument");this.bitData=r.slice()}static makeBytes(t){const e=[];for(const r of t)appendBits(r,8,e);return new QrSegment(Mode.BYTE,t.length,e)}static makeNumeric(t){if(!QrSegment.isNumeric(t))throw new RangeError("String contains non-numeric characters");const e=[];for(let r=0;r<t.length;){const o=Math.min(t.length-r,3);appendBits(parseInt(t.substring(r,r+o),10),3*o+1,e),r+=o}return new QrSegment(Mode.NUMERIC,t.length,e)}static makeAlphanumeric(t){if(!QrSegment.isAlphanumeric(t))throw new RangeError("String contains unencodable characters in alphanumeric mode");const e=[];let r;for(r=0;r+2<=t.length;r+=2){let o=45*QrSegment.ALPHANUMERIC_CHARSET.indexOf(t.charAt(r));o+=QrSegment.ALPHANUMERIC_CHARSET.indexOf(t.charAt(r+1)),appendBits(o,11,e)}return r<t.length&&appendBits(QrSegment.ALPHANUMERIC_CHARSET.indexOf(t.charAt(r)),6,e),new QrSegment(Mode.ALPHANUMERIC,t.length,e)}static makeSegments(t){return""===t?[]:QrSegment.isNumeric(t)?[QrSegment.makeNumeric(t)]:QrSegment.isAlphanumeric(t)?[QrSegment.makeAlphanumeric(t)]:[QrSegment.makeBytes(QrSegment.toUtf8ByteArray(t))]}static makeEci(t){const e=[];if(t<0)throw new RangeError("ECI assignment value out of range");if(t<128)appendBits(t,8,e);else if(t<16384)appendBits(2,2,e),appendBits(t,14,e);else{if(!(t<1e6))throw new RangeError("ECI assignment value out of range");appendBits(6,3,e),appendBits(t,21,e)}return new QrSegment(Mode.ECI,0,e)}static isNumeric(t){return QrSegment.NUMERIC_REGEX.test(t)}static isAlphanumeric(t){return QrSegment.ALPHANUMERIC_REGEX.test(t)}getData(){return this.bitData.slice()}static getTotalBits(t,e){let r=0;for(const o of t){const t=o.mode.numCharCountBits(e);if(o.numChars>=1<<t)return 1/0;r+=4+t+o.bitData.length}return r}static toUtf8ByteArray(t){const e=encodeURI(t),r=[];for(let t=0;t<e.length;t++)"%"!==e.charAt(t)?r.push(e.charCodeAt(t)):(r.push(parseInt(e.substring(t+1,t+3),16)),t+=2);return r}}QrSegment.NUMERIC_REGEX=/^[0-9]*$/,QrSegment.ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+.\/:-]*$/,QrSegment.ALPHANUMERIC_CHARSET="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";export class QrCode{constructor(t,e,r,o){this.modules=[],this.isFunction=[];let s=o;if(this.version=t,this.errorCorrectionLevel=e,t<QrCode.MIN_VERSION||t>QrCode.MAX_VERSION)throw new RangeError("Version value out of range");if(s<-1||s>7)throw new RangeError("Mask value out of range");this.size=4*t+17;const n=[];for(let t=0;t<this.size;t++)n.push(!1);for(let t=0;t<this.size;t++)this.modules.push(n.slice()),this.isFunction.push(n.slice());this.drawFunctionPatterns();const i=this.addEccAndInterleave(r);if(this.drawCodewords(i),-1===s){let t=1e9;for(let e=0;e<8;e++){this.applyMask(e),this.drawFormatBits(e);const r=this.getPenaltyScore();r<t&&(s=e,t=r),this.applyMask(e)}}assert(s>=0&&s<=7),this.mask=s,this.applyMask(s),this.drawFormatBits(s),this.isFunction=[]}static encodeText(t,e){const r=QrSegment.makeSegments(t);return QrCode.encodeSegments(r,e)}static encodeBinary(t,e){const r=QrSegment.makeBytes(t);return QrCode.encodeSegments([r],e)}static encodeSegments(t,e,r=1,o=40,s=-1,n=!0){if(!(QrCode.MIN_VERSION<=r&&r<=o&&o<=QrCode.MAX_VERSION)||s<-1||s>7)throw new RangeError("Invalid value");let i,a;for(i=r;;i++){const r=8*QrCode.getNumDataCodewords(i,e),s=QrSegment.getTotalBits(t,i);if(s<=r){a=s;break}if(i>=o)throw new RangeError("Data too long")}let h=e;for(const t of[Ecc.MEDIUM,Ecc.QUARTILE,Ecc.HIGH])n&&a<=8*QrCode.getNumDataCodewords(i,t)&&(h=t);const l=[];for(const e of t){appendBits(e.mode.modeBits,4,l),appendBits(e.numChars,e.mode.numCharCountBits(i),l);for(const t of e.getData())l.push(t)}assert(l.length===a);const d=8*QrCode.getNumDataCodewords(i,h);assert(l.length<=d),appendBits(0,Math.min(4,d-l.length),l),appendBits(0,(8-l.length%8)%8,l),assert(l.length%8==0);for(let t=236;l.length<d;t^=253)appendBits(t,8,l);const c=[];for(;8*c.length<l.length;)c.push(0);return l.forEach((t,e)=>{c[e>>>3]|=t<<7-(7&e)}),new QrCode(i,h,c,s)}getModule(t,e){return t>=0&&t<this.size&&e>=0&&e<this.size&&this.modules[e][t]}getModules(){return this.modules}drawFunctionPatterns(){for(let t=0;t<this.size;t++)this.setFunctionModule(6,t,t%2==0),this.setFunctionModule(t,6,t%2==0);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);const t=this.getAlignmentPatternPositions(),e=t.length;for(let r=0;r<e;r++)for(let o=0;o<e;o++)0===r&&0===o||0===r&&o===e-1||r===e-1&&0===o||this.drawAlignmentPattern(t[r],t[o]);this.drawFormatBits(0),this.drawVersion()}drawFormatBits(t){const e=this.errorCorrectionLevel.formatBits<<3|t;let r=e;for(let t=0;t<10;t++)r=r<<1^1335*(r>>>9);const o=21522^(e<<10|r);assert(o>>>15==0);for(let t=0;t<=5;t++)this.setFunctionModule(8,t,getBit(o,t));this.setFunctionModule(8,7,getBit(o,6)),this.setFunctionModule(8,8,getBit(o,7)),this.setFunctionModule(7,8,getBit(o,8));for(let t=9;t<15;t++)this.setFunctionModule(14-t,8,getBit(o,t));for(let t=0;t<8;t++)this.setFunctionModule(this.size-1-t,8,getBit(o,t));for(let t=8;t<15;t++)this.setFunctionModule(8,this.size-15+t,getBit(o,t));this.setFunctionModule(8,this.size-8,!0)}drawVersion(){if(this.version<7)return;let t=this.version;for(let e=0;e<12;e++)t=t<<1^7973*(t>>>11);const e=this.version<<12|t;assert(e>>>18==0);for(let t=0;t<18;t++){const r=getBit(e,t),o=this.size-11+t%3,s=Math.floor(t/3);this.setFunctionModule(o,s,r),this.setFunctionModule(s,o,r)}}drawFinderPattern(t,e){for(let r=-4;r<=4;r++)for(let o=-4;o<=4;o++){const s=Math.max(Math.abs(o),Math.abs(r)),n=t+o,i=e+r;n>=0&&n<this.size&&i>=0&&i<this.size&&this.setFunctionModule(n,i,2!==s&&4!==s)}}drawAlignmentPattern(t,e){for(let r=-2;r<=2;r++)for(let o=-2;o<=2;o++)this.setFunctionModule(t+o,e+r,1!==Math.max(Math.abs(o),Math.abs(r)))}setFunctionModule(t,e,r){this.modules[e][t]=r,this.isFunction[e][t]=!0}addEccAndInterleave(t){const e=this.version,r=this.errorCorrectionLevel;if(t.length!==QrCode.getNumDataCodewords(e,r))throw new RangeError("Invalid argument");const o=QrCode.NUM_ERROR_CORRECTION_BLOCKS[r.ordinal][e],s=QrCode.ECC_CODEWORDS_PER_BLOCK[r.ordinal][e],n=Math.floor(QrCode.getNumRawDataModules(e)/8),i=o-n%o,a=Math.floor(n/o),h=[],l=QrCode.reedSolomonComputeDivisor(s);for(let e=0,r=0;e<o;e++){const o=t.slice(r,r+a-s+(e<i?0:1));r+=o.length;const n=QrCode.reedSolomonComputeRemainder(o,l);e<i&&o.push(0),h.push(o.concat(n))}const d=[];for(let t=0;t<h[0].length;t++)h.forEach((e,r)=>{(t!==a-s||r>=i)&&d.push(e[t])});return assert(d.length===n),d}drawCodewords(t){if(t.length!==Math.floor(QrCode.getNumRawDataModules(this.version)/8))throw new RangeError("Invalid argument");let e=0;for(let r=this.size-1;r>=1;r-=2){6===r&&(r=5);for(let o=0;o<this.size;o++)for(let s=0;s<2;s++){const n=r-s,i=!(r+1&2)?this.size-1-o:o;!this.isFunction[i][n]&&e<8*t.length&&(this.modules[i][n]=getBit(t[e>>>3],7-(7&e)),e++)}}assert(e===8*t.length)}applyMask(t){if(t<0||t>7)throw new RangeError("Mask value out of range");for(let e=0;e<this.size;e++)for(let r=0;r<this.size;r++){let o;switch(t){case 0:o=(r+e)%2==0;break;case 1:o=e%2==0;break;case 2:o=r%3==0;break;case 3:o=(r+e)%3==0;break;case 4:o=(Math.floor(r/3)+Math.floor(e/2))%2==0;break;case 5:o=r*e%2+r*e%3==0;break;case 6:o=(r*e%2+r*e%3)%2==0;break;case 7:o=((r+e)%2+r*e%3)%2==0;break;default:throw new Error("Unreachable")}!this.isFunction[e][r]&&o&&(this.modules[e][r]=!this.modules[e][r])}}getPenaltyScore(){let t=0;for(let e=0;e<this.size;e++){let r=!1,o=0;const s=[0,0,0,0,0,0,0];for(let n=0;n<this.size;n++)this.modules[e][n]===r?(o++,5===o?t+=QrCode.PENALTY_N1:o>5&&t++):(this.finderPenaltyAddHistory(o,s),r||(t+=this.finderPenaltyCountPatterns(s)*QrCode.PENALTY_N3),r=this.modules[e][n],o=1);t+=this.finderPenaltyTerminateAndCount(r,o,s)*QrCode.PENALTY_N3}for(let e=0;e<this.size;e++){let r=!1,o=0;const s=[0,0,0,0,0,0,0];for(let n=0;n<this.size;n++)this.modules[n][e]===r?(o++,5===o?t+=QrCode.PENALTY_N1:o>5&&t++):(this.finderPenaltyAddHistory(o,s),r||(t+=this.finderPenaltyCountPatterns(s)*QrCode.PENALTY_N3),r=this.modules[n][e],o=1);t+=this.finderPenaltyTerminateAndCount(r,o,s)*QrCode.PENALTY_N3}for(let e=0;e<this.size-1;e++)for(let r=0;r<this.size-1;r++){const o=this.modules[e][r];o===this.modules[e][r+1]&&o===this.modules[e+1][r]&&o===this.modules[e+1][r+1]&&(t+=QrCode.PENALTY_N2)}let e=0;for(const t of this.modules)e=t.reduce((t,e)=>t+(e?1:0),e);const r=this.size*this.size,o=Math.ceil(Math.abs(20*e-10*r)/r)-1;return assert(o>=0&&o<=9),t+=o*QrCode.PENALTY_N4,assert(t>=0&&t<=2568888),t}getAlignmentPatternPositions(){if(1===this.version)return[];const t=Math.floor(this.version/7)+2,e=32===this.version?26:2*Math.ceil((4*this.version+4)/(2*t-2)),r=[6];for(let o=this.size-7;r.length<t;o-=e)r.splice(1,0,o);return r}static getNumRawDataModules(t){if(t<QrCode.MIN_VERSION||t>QrCode.MAX_VERSION)throw new RangeError("Version number out of range");let e=(16*t+128)*t+64;if(t>=2){const r=Math.floor(t/7)+2;e-=(25*r-10)*r-55,t>=7&&(e-=36)}return assert(e>=208&&e<=29648),e}static getNumDataCodewords(t,e){return Math.floor(QrCode.getNumRawDataModules(t)/8)-QrCode.ECC_CODEWORDS_PER_BLOCK[e.ordinal][t]*QrCode.NUM_ERROR_CORRECTION_BLOCKS[e.ordinal][t]}static reedSolomonComputeDivisor(t){if(t<1||t>255)throw new RangeError("Degree out of range");const e=[];for(let r=0;r<t-1;r++)e.push(0);e.push(1);let r=1;for(let o=0;o<t;o++){for(let t=0;t<e.length;t++)e[t]=QrCode.reedSolomonMultiply(e[t],r),t+1<e.length&&(e[t]^=e[t+1]);r=QrCode.reedSolomonMultiply(r,2)}return e}static reedSolomonComputeRemainder(t,e){const r=e.map(()=>0);for(const o of t){const t=o^r.shift();r.push(0),e.forEach((e,o)=>{r[o]^=QrCode.reedSolomonMultiply(e,t)})}return r}static reedSolomonMultiply(t,e){if(t>>>8!=0||e>>>8!=0)throw new RangeError("Byte out of range");let r=0;for(let o=7;o>=0;o--)r=r<<1^285*(r>>>7),r^=(e>>>o&1)*t;return assert(r>>>8==0),r}finderPenaltyCountPatterns(t){const e=t[1];assert(e<=3*this.size);const r=e>0&&t[2]===e&&t[3]===3*e&&t[4]===e&&t[5]===e;return(r&&t[0]>=4*e&&t[6]>=e?1:0)+(r&&t[6]>=4*e&&t[0]>=e?1:0)}finderPenaltyTerminateAndCount(t,e,r){let o=e;return t&&(this.finderPenaltyAddHistory(o,r),o=0),o+=this.size,this.finderPenaltyAddHistory(o,r),this.finderPenaltyCountPatterns(r)}finderPenaltyAddHistory(t,e){let r=t;0===e[0]&&(r+=this.size),e.pop(),e.unshift(r)}}QrCode.MIN_VERSION=1,QrCode.MAX_VERSION=40,QrCode.PENALTY_N1=3,QrCode.PENALTY_N2=3,QrCode.PENALTY_N3=40,QrCode.PENALTY_N4=10,QrCode.ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],QrCode.NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]];