qr code micro 2 encoder logic
encoder/getModeBitArray[1, 2, 4, 8] available.QR Code is a registered trademark of DENSO WAVE INCORPORATED in Japan and in other countries.
encoder
getModeBitArray
01. declare characters[cs1: alphanumeric, cs3: kanji]this.cs1=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:`
this.cs3=``02. set cs3
(()=>{
const vs=[],decoder=new TextDecoder(`sjis`)
,c=(x,y,subtrahend)=>{
const v=decoder.decode(new Uint8Array([y,x]))
if(1!==v.length||`\ufffd`===v||this.cs3.includes(v))return
this.cs3+=v
vs.push((v=>0xc0*(v>>>8)+(0xff&v))((y<<8|x)-subtrahend))
}
for(let x=0x40;x<0xfd;x++)if(0x7f!==x){
for(let y=0x81;y<0xa0;y++)c(x,y,0x8140)
for(let y=0xe0;y<0xec;y++)if(0xeb>y||0xc0>x)c(x,y,0xc140)
}
return vs
})()03. declare values
[
[mode indicator, bit length]
,[character count indicator, bit length]
]04. set values
if(0b0001===mode)forEach(false,v.match(/.{1,3}/g),v=>vs.push([Number(v),1+3*v.length]))
else if(0b0010===mode)forEach(false,v.match(/.{1,2}/g),v=>vs.push(2===v.length?[this.cs1.length*c0(v[0])+c0(v[1]),11]:[c0(v[0]),6]))
else if(0b0100===mode)forEach(false,v,v=>vs.push([v,8]))
else if(0b1000===mode)forEach(false,v,v=>vs.push([c1(v),13]))05. return
return flatMap(false,vs,v=>v[0].toBitArray(v[1]))encodeMicro, encode2
01. declare pack, rs, getC4, placeconst pack=(v,dataBitLength,terminatorLength)=>{
let difference=dataBitLength-v.length
if(0>difference)throw Error()
if(0!==difference)v.addLength(terminatorLength.limit(true,difference))
v=v.toArrayFromBit()
difference=(dataBitLength>>>3)-v.length
if(0<difference)forEach(false,difference,(_,i)=>v.push(1&i?0x11:0xec))
return v
}
,rs=new RS(new GF(0x11d),new Uint8Array([2,5,6,7,8,10,13,14,15,16,17,18,20,22,24,25,26,28,30]))
,getC4=(size,vs,getIndex)=>(c=>([x,y],r,v)=>forEach(false,r<<1,(_,i)=>{
i-=r
c(x+i,y-r,v)
c(x+r,y+i,v)
c(x-i,y+r,v)
c(x-r,y-i,v)
}))((x,y,v)=>-1<x&&-1<y&&size>x&&size>y&&(vs[getIndex(x,y)]=v))
,place=(v,size,vs,getIndex,masks,mask,timingX)=>{
let bitCount=0
const c=(x,y)=>{
const i=getIndex(x,y)
if(undefined!==vs[i])return
vs[i]=1&v[bitCount++]
if(masks[mask](x,y))vs[i]^=1
}
for(let b,v=size>>>1;v--;b=!b)for(let y=size;y--;)((x,y)=>{
if(timingX<x)x++
if(b)y=size-y-1
c(1+x,y)
c(x,y)
})(v<<1,y)
}encodeMicro
02. declare ecCodewordCounts, bitLengthsconst ecCodewordCounts=[
[ 8, 6, 5, 2]
,[10, 8, 6]
,[14]
]
,bitLengths=map(false,new Uint8Array(4),(_,i)=>(size=>size**2-2*size-63)(11+2*i))03. declare values
const vs=((i0,i1)=>[ecCodewordCounts[i0][i1]])(1^level,4-version)04. declare dataBitLength
,dataBitLength=bitLengths[version-1]-(vs[0]<<3)05. declare quotient, remainder
none06. declare interleave
none07. set byte array
v=pack(v,dataBitLength,1+(version<<1))
if(dataBitLength>v.length<<3)v.addLength(1)08. set bit array
v=[(v=>{
if([1,3].includes(version))v.splice(-4)
return v
})(flatMap(false,v,v=>v.toBitArray(8))),flatMap(false,rs.encode(v,vs[0]),v=>v.toBitArray(8))].flatten()09. declare size, values
const size=9+2*version,vs=Array(size**2)10. declare getIndex
,getIndex=(x,y)=>x+y*size11. set timing pattern
forEach(false,size-8,(_,i)=>(i=>vs[i]=vs[i*size]=1^1&i)(8+i))12. set finder pattern
const c4=getC4(size,vs,getIndex)
forEach(false,[[3,3]],v=>{
c4(v,2,0)
c4(v,4,0)
vs[getIndex(v[0],v[1])]=1
c4(v,1,1)
c4(v,3,1)
})13. set alignment pattern
none14. set values
none15. set version information
none16. declare masks, symbol, encode[set format information, ...]
const masks=[
(x,y)=>0===y%2
,(x,y)=>0===((x/3>>>0)+(y/2>>>0))%2
,(x,y)=>0===((x*y)%2+(x*y)%3)%2
,(x,y)=>0===((x+y)%2+(x*y)%3)%2
]
,symbol=[
[0]
,[1,2]
,[3,4]
,[5,6,7]
][version-1][1^level]
,encode=(mask,vs)=>{
forEach(false,(0x4445^(0x537).toBCH(symbol<<2|mask)).toBitArray(15),(v,i)=>vs[8>i?getIndex(1+i,8):getIndex(8,15-i)]=v)
place(v,size,vs,getIndex,masks,mask,-1)
return vs
}17. return
return -1===mask?reduce(false,masks,(c=>(a,_,i)=>{
const v=(v=>[v,c(v)])(encode(i,[...vs]))
return !i||a[1]<v[1]?v:a
})(v=>{
let sum1=0,sum2=0
forEach(false,size-1,(_,i)=>{
sum1+=v[getIndex(size-1,1+i)]
sum2+=v[getIndex(1+i,size-1)]
})
return sum1>sum2?(sum2<<4)+sum1:(sum1<<4)+sum2
}))[0]:encode(mask,vs)encode2
02. declare ecCodewordCounts, ecBlockCounts, bitLengthsconst ecCodewordCounts=[
[ 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]
,[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]
,[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]
,[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]
]
,ecBlockCounts=[
[ 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, 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, 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, 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]
]
,bitLengths=map(false,new Uint16Array(40),(_,i)=>((version,size)=>{
let v=size**2-2*size-191
if(1===version)return v
const n=version/7>>>0
v-=25*((2+n)**2-3)
if(6<version)v-=36-10*n
return v
})(1+i,21+4*i))03. declare values
const vs=((i0,i1)=>[ecCodewordCounts[i0][i1],ecBlockCounts[i0][i1]])(1^level,version-1)04. declare dataBitLength
,dataBitLength=bitLengths[version-1]-(vs[1]*vs[0]<<3)05. declare quotient, remainder
,[quotient,remainder]=(v=>[v/vs[1]>>>0,v%vs[1]])(dataBitLength>>>3)06. declare interleave
,c=(v,vs)=>reduce(false,v,(a,_,i)=>forEach(false,vs,v=>undefined===v[i]||a.push(v[i]))||a,[])07. set byte array
v=pack(v,dataBitLength,4)08. set bit array
v=flatMap(false,[c(remainder?1+quotient:quotient,v=reduce(false,vs[1],(a,_,i)=>{
const addend=vs[1]-remainder>i?quotient:1+quotient
if(i)i=reduce(false,a,(a,v)=>a+v.length,0)
a.push(v.slice(i,i+addend))
return a
},[])),c(vs[0],map(false,v,v=>rs.encode(v,vs[0])))].flatten(),v=>v.toBitArray(8))09. declare size, values
const size=17+4*version,vs=Array(size**2)10. declare getIndex
,getIndex=(x,y)=>x+y*size11. set timing pattern
forEach(false,size-16,(_,i)=>(i=>vs[getIndex(6,i)]=vs[getIndex(i,6)]=1^1&i)(8+i))12. set finder pattern
const c4=getC4(size,vs,getIndex)
forEach(false,[[3,3],[size-4,3],[3,size-4]],v=>{
c4(v,2,0)
c4(v,4,0)
vs[getIndex(v[0],v[1])]=1
c4(v,1,1)
c4(v,3,1)
})13. set alignment pattern
if(1<version)forEach(false,(v=>(step=>reduce(false,v,(a,_,i)=>{
a[1+i]=a[i]-step
return a
},[size-7]))((v=>v>(v=v>>>1<<1)?2+v:v)((size-13)/(1+v))))(version/7>>>0),(c=>(v,_,vs)=>{
if(size-7>v)forEach(false,[[v,6],[6,v]],c)
forEach(false,vs,x=>c([x,v]))
})(v=>{
c4(v,1,0)
vs[getIndex(v[0],v[1])]=1
c4(v,2,1)
}))14. set values
vs[getIndex(8,size-8)]=115. set version information
if(6<version)forEach(false,(0x1f25).toBCH(version).toBitArray(18),(v,i)=>((a,b)=>vs[getIndex(a,b)]=vs[getIndex(b,a)]=v)(size-i%3-9,5-(i/3>>>0)))16. declare masks, encode[set format information, ...]
const masks=[
(x,y)=>0===(x+y)%2
,(x,y)=>0===y%2
,(x,y)=>0===x%3
,(x,y)=>0===(x+y)%3
,(x,y)=>0===((x/3>>>0)+(y/2>>>0))%2
,(x,y)=>0===(x*y)%2+(x*y)%3
,(x,y)=>0===((x*y)%2+(x*y)%3)%2
,(x,y)=>0===((x+y)%2+(x*y)%3)%2
]
,encode=(mask,vs)=>{
forEach(false,(0x5412^(0x537).toBCH(level<<3|mask)).toBitArray(15),(v,i)=>vs[6>i?getIndex(i,8):8>i?getIndex(1+i,8):getIndex(8,8===i?7:14-i)]=vs[7>i?getIndex(8,size-i-1):getIndex(size+i-15,8)]=v)
place(v,size,vs,getIndex,masks,mask,5)
return vs
}17. return
return -1===mask?reduce(false,masks,(c=>(a,_,i)=>{
const v=(v=>[v,c(v)])(encode(i,[...vs]))
return !i||a[1]>v[1]?v:a
})(v=>reduce(false,size,(a,_,y)=>{
let row=``,col=``
forEach(false,size,(_,x)=>{
const i=getIndex(x,y)
row+=v[i]
col+=v[getIndex(y,x)]
if(y<size-1&&x<size-1&&v[i]===v[getIndex(1+x,y)]&&v[i]===v[getIndex(x,1+y)]&&v[i]===v[getIndex(1+x,1+y)])a+=3
})
return a+reduce(false,[row,col],(a,v)=>a+v.matchAll(/0{5,}|1{5,}/g).reduce((a,v)=>a+v[0].length-2,0)+40*`0000${v}0000`.matchAll(/(?=[0]{4,}10111010|01011101[0]{4,})/g).reduce(a=>++a,0),0)
},0)+10*(abs(50-(100*reduce(false,v,(a,v)=>a+v,0)/size**2>>>0))/5>>>0)))[0]:encode(mask,vs)