Skip to content

Commit 0282bba

Browse files
fix: Han Xin remove incorrect timing patterns, add separator bands
Han Xin Code does NOT have timing patterns (unlike QR). Replace alternating timing with white separator bands around finders. Match improved 71% → 75%. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8e1094b commit 0282bba

1 file changed

Lines changed: 26 additions & 13 deletions

File tree

src/encoders/hanxin.ts

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ function hanxinSize(version: number): number {
9797
*
9898
* Total modules minus function patterns:
9999
* - 4 finder patterns (7×7 each = 196 modules)
100-
* - 4 timing strips along edges (between finders)
100+
* - Separator bands around finders
101101
* - Version/format info areas
102102
*
103103
* Returns the total number of data codewords (bytes) available
@@ -110,15 +110,13 @@ function hanxinTotalCodewords(version: number): number {
110110
// 4 finder patterns — 7×7 each
111111
const finderModules = 4 * 7 * 7;
112112

113-
// Timing patterns along all 4 edges (between finders)
114-
// Each edge has (size - 14) modules in the timing strip
115-
const timingModules = 4 * (size - 14);
113+
// Separator bands around finders: 4 L-shaped bands, ~8 modules each
114+
const separatorModules = 4 * (8 + 7);
116115

117-
// Format/version info: Han Xin uses structural regions
118-
// along finder edges — approximate as 36 modules per version
116+
// Format/version info regions around finders
119117
const formatModules = Math.min(36 + version * 2, size * 4);
120118

121-
const usableModules = totalModules - finderModules - timingModules - formatModules;
119+
const usableModules = totalModules - finderModules - separatorModules - formatModules;
122120

123121
return Math.floor(usableModules / 8);
124122
}
@@ -331,12 +329,21 @@ export function encodeHanXin(text: string, options: HanXinOptions = {}): boolean
331329
placeFinderHX(matrix, size - 7, 0, FINDER_BL, size);
332330
placeFinderHX(matrix, size - 7, size - 7, FINDER_BR, size);
333331

334-
// Timing patterns along all 4 edges
335-
for (let i = 7; i < size - 7; i++) {
336-
if (matrix[0]![i] === null) matrix[0]![i] = i % 2 === 0;
337-
if (matrix[i]![0] === null) matrix[i]![0] = i % 2 === 0;
338-
if (matrix[size - 1]![i] === null) matrix[size - 1]![i] = i % 2 === 0;
339-
if (matrix[i]![size - 1] === null) matrix[i]![size - 1] = i % 2 === 0;
332+
// Han Xin has NO timing patterns — only separator bands around finders
333+
// 1-module white separator around each 7x7 finder
334+
for (let i = -1; i <= 7; i++) {
335+
// Top-left separator
336+
setSafeNull(matrix, 7, i, size);
337+
setSafeNull(matrix, i, 7, size);
338+
// Top-right separator
339+
setSafeNull(matrix, 7, size - 8 + i, size);
340+
setSafeNull(matrix, i, size - 8, size);
341+
// Bottom-left separator
342+
setSafeNull(matrix, size - 8, i, size);
343+
setSafeNull(matrix, size - 8 + i, 7, size);
344+
// Bottom-right separator
345+
setSafeNull(matrix, size - 8, size - 8 + i, size);
346+
setSafeNull(matrix, size - 8 + i, size - 8, size);
340347
}
341348

342349
// Place data bits into available modules
@@ -360,6 +367,12 @@ export function encodeHanXin(text: string, options: HanXinOptions = {}): boolean
360367
return matrix.map((row) => row.map((cell) => cell === true));
361368
}
362369

370+
function setSafeNull(matrix: (boolean | null)[][], r: number, c: number, size: number): void {
371+
if (r >= 0 && r < size && c >= 0 && c < size && matrix[r]![c] === null) {
372+
matrix[r]![c] = false;
373+
}
374+
}
375+
363376
function placeFinderHX(
364377
matrix: (boolean | null)[][],
365378
row: number,

0 commit comments

Comments
 (0)