diff --git a/packages/core/src/encoder/Encoder.ts b/packages/core/src/encoder/Encoder.ts index 61e49156..565b850e 100644 --- a/packages/core/src/encoder/Encoder.ts +++ b/packages/core/src/encoder/Encoder.ts @@ -9,12 +9,12 @@ import { appendModeInfo, appendTerminator, calculateBitsNeeded, - chooseBestMask, + chooseBestMaskAndMatrix, + chooseRecommendVersion, Hints, injectECCodewords, isByteMode, isHanziMode, - recommendVersion, Segment, SegmentBlock, willFit @@ -23,8 +23,6 @@ import { Encoded } from './Encoded'; import { Charset } from '/common/Charset'; import { ECLevel } from '/common/ECLevel'; import { BitArray } from '/common/BitArray'; -import { buildMatrix } from './utils/matrix'; -import { ByteMatrix } from '/common/ByteMatrix'; import { Version, VERSIONS } from '/common/Version'; import { encode as contentEncode, TextEncode } from '/common/encoding'; import { assertHints, assertLevel, assertVersion } from './utils/asserts'; @@ -106,7 +104,7 @@ export class Encoder { let version: Version; if (versionNumber === 'Auto') { - version = recommendVersion(segmentBlocks, ecLevel); + version = chooseRecommendVersion(segmentBlocks, ecLevel); } else { version = VERSIONS[versionNumber - 1]; @@ -131,11 +129,8 @@ export class Encoder { appendTerminator(headAndDataBits, ecBlocks.numTotalDataCodewords); - const matrix = new ByteMatrix(version.size); const codewords = injectECCodewords(headAndDataBits, ecBlocks); - const mask = chooseBestMask(matrix, codewords, version, ecLevel); - - buildMatrix(matrix, codewords, version, ecLevel, mask); + const [mask, matrix] = chooseBestMaskAndMatrix(codewords, version, ecLevel); return new Encoded(matrix, version, ecLevel, mask); } diff --git a/packages/core/src/encoder/utils/encoder.ts b/packages/core/src/encoder/utils/encoder.ts index 81e6cd2c..d57feb1d 100644 --- a/packages/core/src/encoder/utils/encoder.ts +++ b/packages/core/src/encoder/utils/encoder.ts @@ -210,7 +210,7 @@ export function calculateBitsNeeded(segmentBlocks: SegmentBlock[], version: Vers return bitsNeeded; } -export function recommendVersion(segmentBlocks: SegmentBlock[], ecLevel: ECLevel): Version { +export function chooseRecommendVersion(segmentBlocks: SegmentBlock[], ecLevel: ECLevel): Version { // Hard part: need to know version to know how many bits length takes. But need to know how many // bits it takes to know version. First we take a guess at version by assuming version will be // the minimum, 1: @@ -222,22 +222,27 @@ export function recommendVersion(segmentBlocks: SegmentBlock[], ecLevel: ECLevel return chooseVersion(bitsNeeded, ecLevel); } -export function chooseBestMask(matrix: ByteMatrix, bits: BitArray, version: Version, ecLevel: ECLevel): number { - let bestMask = -1; - // Lower penalty is better. - let minPenalty = Number.MAX_VALUE; - - // We try all mask patterns to choose the best one. - for (let mask = 0; mask < 8; mask++) { - buildMatrix(matrix, bits, version, ecLevel, mask); +export function chooseBestMaskAndMatrix( + bits: BitArray, + version: Version, + ecLevel: ECLevel +): [mask: number, matrix: ByteMatrix] { + let bestMask = 0; + let bestMatrix = buildMatrix(bits, version, ecLevel, bestMask); + let minPenalty = calculateMaskPenalty(bestMatrix); + // We try all rest mask patterns to choose the best one. + for (let mask = 1; mask < 8; mask++) { + const matrix = buildMatrix(bits, version, ecLevel, mask); const penalty = calculateMaskPenalty(matrix); + // Lower penalty is better. if (penalty < minPenalty) { bestMask = mask; + bestMatrix = matrix; minPenalty = penalty; } } - return bestMask; + return [bestMask, bestMatrix]; } diff --git a/packages/core/src/encoder/utils/matrix.ts b/packages/core/src/encoder/utils/matrix.ts index b03f7281..b02d4258 100644 --- a/packages/core/src/encoder/utils/matrix.ts +++ b/packages/core/src/encoder/utils/matrix.ts @@ -339,7 +339,9 @@ function embedEncodingRegion(matrix: ByteMatrix, codewords: BitArray, version: V // Build 2D matrix of QR Code from "codewords" with "ecLevel", "version" and "getMaskPattern". On // success, store the result in "matrix". -export function buildMatrix(matrix: ByteMatrix, codewords: BitArray, version: Version, ecLevel: ECLevel, mask: number): void { +export function buildMatrix(codewords: BitArray, version: Version, ecLevel: ECLevel, mask: number): ByteMatrix { + const matrix = new ByteMatrix(version.size); + // Clear matrix matrix.clear(-1); @@ -347,4 +349,6 @@ export function buildMatrix(matrix: ByteMatrix, codewords: BitArray, version: Ve embedFunctionPatterns(matrix, version); // Embed encoding region embedEncodingRegion(matrix, codewords, version, ecLevel, mask); + + return matrix; }