为什么我的二维码生成过程中会留下未定义的模块?

Why are undefined modules left during my QR code generation?

我尝试用 JavaScript 生成二维码。根据一些教程,生成必须放置在 QR 矩阵内的位串是可行的,我的位串(由交错数据码字、交错纠错码字和其余位组成)与教程中的示例相同。因此我相信我在放置 QR 码模块时犯了一个错误,由函数 addDataToMatrix.

完成

对于版本一到版本五的 QR 码,一切似乎都有效。但是对于高于六的二维码版本,并不是二维二维矩阵的所有模块都会被填充,其中一些会留下“未定义”。

这是一个例子:

// input string: Why are these damned undefined modules left after the placement?
// alternative string: Hello, world!

// error correction level: H
let version=7;
// version for alternative input / bit string: 2

// generated bit string (interleaved data codewords, interleaved error correction codewords, remainder bits)
let bitString="01000100001101100101011000110010010001100000010101010010011001100000011010000110011101100000011010010110110001100101001010000111010001101110011001010110000001111001001000010110010101100110011100000110000001101101011001000010010000101100011000010111111001100000011000000110000101100010011001010110110101100001011000110110010100100100001011110110011001110101011000000111000001110100011101000110110101100100011001010110010101100101011101010110100001101110011011000110001000101110011101010111010001100101011100000111010000111111000011011100001100010001110000110010011010101110100101101100011000100101101001001010010100000000010100001000011110101000100110011100111000101000011001011010110100110001100101011101110111110011111000100010011100110110011010001110010100111001111110011010011011010010110100010011110011101100001010000101110111110100101111000011010101011111001001000011010011111101010110101111000001010110100111010011011001101111001111111011010101101111010011010101001100010010000101100101101110011101100111001100010010100101010101100011010011100110000100111000000101000000010101101010111010011100111010100100101010111110100001111101101100110001100101010001101001010011101110000001101000010000100010010110111000111000000010110100000111110110111010100111101010001001100001001010010100100110010100110010011011100011100011001100100100000000100111010110111000101100010011110000011110011111011001011011110101101000000000010101000110000011000011010111101111010110010101011110011000100010111111111000101000000001000011001011110101001010001010010111110100011011011110110011";
// alternative bit string: 01000000110101001000011001010110110001101100011011110010110000100000011101110110111101110010011011000110010000100001000011101100011011110111111010111111101011111101001111001100010110100111111000100110000110001111111111101100011000000001011001011100100010011010110110100000010011011111000111000000111000001000111111000011000000110011100111110010000011010000000

const ALIGNMENT_PATTERN_COORDINATES={
    coordinates1: [18, 22, 26, 30, 34, 22, 24, 26, 28, 30, 32, 34, 26, 26, 26, 30, 30, 30, 34, 28, 26, 30, 28, 32, 30, 34, 26, 30, 26, 30, 34, 30, 34, 30, 24, 28, 32, 26, 30],
    coordinates2: [undefined, undefined, undefined, undefined, undefined, 38, 42, 46, 50, 54, 58, 62, 46, 48, 50, 54, 56, 58, 62, 50, 50, 54, 54, 58, 58, 62, 50, 54, 52, 56, 60, 58, 62, 54, 50, 54, 58, 54, 58],
    coordinates3: [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 66, 70, 74, 78, 82, 86, 90, 72, 74, 78, 80, 84, 86, 90, 74, 78, 78, 82, 86, 86, 90, 78, 76, 80, 84, 82, 86],
    coordinates4: [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 94, 98, 102, 106, 110, 114, 118, 98, 102, 104, 108, 112, 114, 118, 102, 102, 106, 110, 110, 114],
    coordinates5: [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 122, 126, 130, 134, 138, 142, 146, 126, 128, 132, 136, 138, 142],
    coordinates6: [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 150, 154, 158, 162, 166, 170]
};

let matrix=generateMatrix(version);
generateSeparators(matrix);
generateFinderPatterns(matrix);
generateAlignmentPatterns(version, matrix);
generateTimingPatterns(matrix);
reserveAreas(version, matrix);
addDataToMatrix(matrix, bitString);
drawMatrix(matrix);

function generateMatrix(version){
    let size=21+(version-1)*4;
  let matrix=[];
    for(let i=0; i<size; i++){
        matrix[i]=[];
        for(let j=0; j<size; j++) matrix[i][j]=undefined;
    }
  matrix[version*4+9][8]=1;
  return matrix;
}

function generateSeparators(matrix){
  for(let i=0; i<8; i++){
        for(let j=0; j<8; j++){
            matrix[i][j]=0;
            matrix[i][matrix[i].length-1-j]=0;
            matrix[matrix[i].length-1-i][j]=0;
        }
    }
}

function generateFinderPatterns(matrix){
    for(let i=0; i<7; i++){
        for(let j=0; j<7; j++){
            matrix[i][j]=1;
            matrix[i][matrix[i].length-1-j]=1;
            matrix[matrix[i].length-1-i][j]=1;
        }
    }
    for(let i=1; i<6; i++){
        for(let j=1; j<6; j++){
            matrix[i][j]=0;
            matrix[i][matrix[i].length-1-j]=0;
            matrix[matrix[i].length-1-i][j]=0;
        }
    }
    for(let i=2; i<5; i++){
        for(let j=2; j<5; j++){
            matrix[i][j]=1;
            matrix[i][matrix[i].length-1-j]=1;
            matrix[matrix[i].length-1-i][j]=1;
        }
    }
}

function generateAlignmentPatterns(version, matrix){
    if(version>1){
        let coordinates=[6, ALIGNMENT_PATTERN_COORDINATES.coordinates1[version-2], ALIGNMENT_PATTERN_COORDINATES.coordinates2[version-2], ALIGNMENT_PATTERN_COORDINATES.coordinates3[version-2], ALIGNMENT_PATTERN_COORDINATES.coordinates4[version-2], ALIGNMENT_PATTERN_COORDINATES.coordinates5[version-2], ALIGNMENT_PATTERN_COORDINATES.coordinates6[version-2]].filter(Number);
        let moduleCenters=[];
        for(let i=0; i<coordinates.length; i++) moduleCenters.push([coordinates[i], coordinates[i]]);
        for(let i=0; i<coordinates.length-1; i++){
            for(let j=i+1; j<coordinates.length; j++){
                moduleCenters.push([coordinates[i], coordinates[j]]);
                moduleCenters.push([coordinates[j], coordinates[i]]);
            }
        }
    for(let i=0; i<moduleCenters.length; i++){
            let isEmpty=true;
            for(let j=-2; j<3; j++){
                for(let k=-2; k<3; k++){
                    if(matrix[moduleCenters[i][0]+j][moduleCenters[i][1]+k]!==undefined) isEmpty=false;
                }
            }
            if(isEmpty){
                for(let j=-2; j<3; j++){
                    for(let k=-2; k<3; k++) matrix[moduleCenters[i][0]+j][moduleCenters[i][1]+k]=1;
                }
                for(let j=-1; j<2; j++){
                    for(let k=-1; k<2; k++) matrix[moduleCenters[i][0]+j][moduleCenters[i][1]+k]=0;
                }
                matrix[moduleCenters[i][0]][moduleCenters[i][1]]=1;
            }
        }
    }
}

function generateTimingPatterns(matrix){
    for(let i=8; i<matrix.length-8; i++){
        matrix[6][i]=(i%2==0)?1:0;
        matrix[i][6]=(i%2==0)?1:0;
    }
}

function reserveAreas(version, matrix){
    if(version<7){
        for(let i=0; i<9; i++){
            if(matrix[i][8]===undefined) matrix[i][8]="reserved";
            if(matrix[8][i]===undefined) matrix[8][i]="reserved";
        }
        for(let i=0; i<8; i++) matrix[8][matrix[8].length-1-i]="reserved";
        for(let i=0; i<7; i++) matrix[matrix[8].length-1-i][8]="reserved";
    }
    else{
        for(let i=0; i<6; i++){
            for(let j=0; j<3; j++){
                matrix[i][matrix[i].length-9-j]="reserved";
                matrix[matrix[i].length-9-j][i]="reserved";
            }
        }
    }
}

function addDataToMatrix(matrix, bitString){
    let j=matrix[0].length-1;
    while(bitString.length>0){
        for(let i=0; i<matrix.length; i++){
            if(bitString.length>0&&matrix[matrix.length-1-i][j]===undefined){
                matrix[matrix.length-1-i][j]=bitString.charAt(bitString.length-1);
                bitString=bitString.slice(0, -1);
            }
            if(bitString.length>0&&matrix[matrix.length-1-i][j-1]===undefined){
                matrix[matrix.length-1-i][j-1]=bitString.charAt(bitString.length-1);
                bitString=bitString.slice(0, -1);
            }
        }
        j-=2;
        if(j==6) j--;
        for(let i=0; i<matrix.length; i++){
            if(bitString.length>0&&matrix[i][j]===undefined){
                matrix[i][j]=bitString.charAt(bitString.length-1);
                bitString=bitString.slice(0, -1);
            }
            if(bitString.length>0&&matrix[i][j-1]===undefined){
                matrix[i][j-1]=bitString.charAt(bitString.length-1);
                bitString=bitString.slice(0, -1);
            }
        }
        j-=2;
    }
}

function drawMatrix(matrix){
    let cssClass;
    let code="";
    for(let i=0; i<matrix.length; i++){
        for(let j=0; j<matrix[i].length; j++){
            if(matrix[i][j]===undefined) cssClass="undefined";
            if(matrix[i][j]=="reserved") cssClass="reserved";
            if(matrix[i][j]==0) cssClass="white";
            if(matrix[i][j]==1) cssClass="black";
            code+='<div class="module '+cssClass+'"></div>';
            if(j==matrix[i].length-1) code+='<div class="break"></div>';
        }
    }
    document.getElementById("result").innerHTML=code;
}
*{
    box-sizing: border-box;
}

#result{
    border-width: 1px;
    border-style: solid;
    border-color: lightgray;
    overflow: auto;
    padding: 28px;
    width: -webkit-max-content;
    width: -moz-max-content;
    width: max-content;
}

.module{
    border-width: 1px;
    border-style: solid;
    border-color: lightgray;
    float: left;
    height: 7px;
    width: 7px;
}
.module.undefined{
    background-color: lightslategray;
}
.module.reserved{
    background-color: lightskyblue;
}
.module.white{
    background-color: white;
}
.module.black{
    background-color: black;
}

.break{
    display: block;
}
<!DOCTYPE html>

<html>

<head>
    <title>QR Generator</title>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
</head>

<body>
  <div id="result"></div>
</body>

</html>

如你所见,输入“为什么这些该死的未定义模块在放置后留下来?”导致位串导致一些未定义的灰色模块。尝试另一个输入,例如“Hello, world!”没有未定义的模块了。

谁能解释一下我哪里出错了?我希望我的例子足够好。

编辑:

我发现给函数addDataToMatrix的位串的长度正好比矩阵中从版本7到版本40的未定义模块总数短30个字符。

我发现了错误。我误解了格式和版本位放置规则。 对于版本 1 到 6,需要格式信息。对于版本 7 到 40,需要版本信息和格式信息。我只放了七到四十版本的二维码版本信息