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, place
const 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, bitLengths
const 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
none

06. declare interleave
none

07. 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*size

11. 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
none

14. set values
none

15. set version information
none

16. 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, bitLengths
const 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*size

11. 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)]=1

15. 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)