@@ -94,19 +94,30 @@ const RMQR_CCI_LENGTHS: [number, number, number, number][] = [
9494 [ 9 , 8 , 8 , 7 ] , // 31: R17x139
9595] ;
9696
97- /** Generate 18-bit rMQR format info with BCH error correction */
98- function rmqrFormatInfo ( formatData : number ) : number {
99- // BCH(18,6) encoding for rMQR format info
100- // Generator polynomial for BCH(18,6)
101- let bch = formatData << 12 ;
102- const gen = 0x1f25 ; // x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1
103- for ( let i = 5 ; i >= 0 ; i -- ) {
104- if ( bch & ( 1 << ( i + 12 ) ) ) {
105- bch ^= gen << i ;
106- }
107- }
108- return ( ( formatData << 12 ) | bch ) ^ 0x1faf2 ; // XOR mask
109- }
97+ // Pre-computed rMQR format info tables from Zint (ISO/IEC 23941)
98+ // Index = version_index + (ecLevel == "H" ? 32 : 0)
99+ // prettier-ignore
100+ const RMQR_FORMAT_LEFT : number [ ] = [
101+ 0x1fab2 , 0x1e597 , 0x1dbdd , 0x1c4f8 , 0x1b86c , 0x1a749 , 0x19903 , 0x18626 ,
102+ 0x17f0e , 0x1602b , 0x15e61 , 0x14144 , 0x13dd0 , 0x122f5 , 0x11cbf , 0x1039a ,
103+ 0x0f1ca , 0x0eeef , 0x0d0a5 , 0x0cf80 , 0x0b314 , 0x0ac31 , 0x0927b , 0x08d5e ,
104+ 0x07476 , 0x06b53 , 0x05519 , 0x04a3c , 0x036a8 , 0x0298d , 0x017c7 , 0x008e2 ,
105+ 0x3f367 , 0x3ec42 , 0x3d208 , 0x3cd2d , 0x3b1b9 , 0x3ae9c , 0x390d6 , 0x38ff3 ,
106+ 0x376db , 0x369fe , 0x357b4 , 0x34891 , 0x33405 , 0x32b20 , 0x3156a , 0x30a4f ,
107+ 0x2f81f , 0x2e73a , 0x2d970 , 0x2c655 , 0x2bac1 , 0x2a5e4 , 0x29bae , 0x2848b ,
108+ 0x27da3 , 0x26286 , 0x25ccc , 0x243e9 , 0x23f7d , 0x22058 , 0x21e12 , 0x20137 ,
109+ ] ;
110+ // prettier-ignore
111+ const RMQR_FORMAT_RIGHT : number [ ] = [
112+ 0x20a7b , 0x2155e , 0x22b14 , 0x23431 , 0x248a5 , 0x25780 , 0x269ca , 0x276ef ,
113+ 0x28fc7 , 0x290e2 , 0x2aea8 , 0x2b18d , 0x2cd19 , 0x2d23c , 0x2ec76 , 0x2f353 ,
114+ 0x30103 , 0x31e26 , 0x3206c , 0x33f49 , 0x343dd , 0x35cf8 , 0x362b2 , 0x37d97 ,
115+ 0x384bf , 0x39b9a , 0x3a5d0 , 0x3baf5 , 0x3c661 , 0x3d944 , 0x3e70e , 0x3f82b ,
116+ 0x003ae , 0x01c8b , 0x022c1 , 0x03de4 , 0x04170 , 0x05e55 , 0x0601f , 0x07f3a ,
117+ 0x08612 , 0x09937 , 0x0a77d , 0x0b858 , 0x0c4cc , 0x0dbe9 , 0x0e5a3 , 0x0fa86 ,
118+ 0x108d6 , 0x117f3 , 0x129b9 , 0x1369c , 0x14a08 , 0x1552d , 0x16b67 , 0x17442 ,
119+ 0x18d6a , 0x1924f , 0x1ac05 , 0x1b320 , 0x1cfb4 , 0x1d091 , 0x1eedb , 0x1f1fe ,
120+ ] ;
110121
111122export interface RMQROptions {
112123 ecLevel ?: "M" | "H" ;
@@ -274,67 +285,30 @@ export function encodeRMQR(text: string, options: RMQROptions = {}): boolean[][]
274285 if ( matrix [ r ] ! [ cols - 1 ] === null ) matrix [ r ] ! [ cols - 1 ] = ( r + 1 ) % 2 === 0 ;
275286 }
276287
277- // 5. Format info (18 bits total: version + EC level encoded with BCH)
278- // Reserve format info positions (around finder and alignment)
279- // Format info left: 3 rows (1,3,5) x 3 cols (8,9,10) + extra positions
280- // Format info right: near bottom-right alignment
281- // For now: use Zint's format lookup tables
282- const formatData = sizeIdx + ( ecLevel === "H" ? 32 : 0 ) ;
283- const formatInfo = rmqrFormatInfo ( formatData ) ;
288+ // 5. Format info from pre-computed Zint tables (18 bits each side)
289+ const fmtIdx = sizeIdx + ( ecLevel === "H" ? 32 : 0 ) ;
290+ const leftFmt = RMQR_FORMAT_LEFT [ fmtIdx ] ! ;
291+ const rightFmt = RMQR_FORMAT_RIGHT [ fmtIdx ] ! ;
284292
285- // Place format info: 18 bits split between left and right sides
286- // Left side: around top-left finder (rows 1-5, cols 8-10)
287- const leftPos : [ number , number ] [ ] = [
288- [ 1 , 8 ] ,
289- [ 2 , 8 ] ,
290- [ 3 , 8 ] ,
291- [ 4 , 8 ] ,
292- [ 5 , 8 ] ,
293- [ 1 , 9 ] ,
294- [ 2 , 9 ] ,
295- [ 3 , 9 ] ,
296- [ 4 , 9 ] ,
297- [ 5 , 9 ] ,
298- [ 1 , 10 ] ,
299- [ 2 , 10 ] ,
300- [ 3 , 10 ] ,
301- [ 4 , 10 ] ,
302- [ 5 , 10 ] ,
303- [ 1 , 11 ] ,
304- [ 2 , 11 ] ,
305- [ 3 , 11 ] ,
306- ] ;
307- for ( let i = 0 ; i < 18 && i < leftPos . length ; i ++ ) {
308- const [ r , c ] = leftPos [ i ] ! ;
309- if ( r < rows && c < cols ) matrix [ r ] ! [ c ] = ( ( formatInfo >> i ) & 1 ) === 1 ;
293+ // Left format info: rows 1-5, cols 8-10 (bit = j*5+i), rows 1-3 col 11 (bits 15-17)
294+ for ( let i = 0 ; i < 5 ; i ++ ) {
295+ for ( let j = 0 ; j < 3 ; j ++ ) {
296+ matrix [ i + 1 ] ! [ j + 8 ] = ( ( leftFmt >> ( j * 5 + i ) ) & 1 ) === 1 ;
297+ }
310298 }
311- // Right side: near bottom-right alignment
312- const rightPos : [ number , number ] [ ] = [
313- [ rows - 6 , arx - 1 ] ,
314- [ rows - 5 , arx - 1 ] ,
315- [ rows - 4 , arx - 1 ] ,
316- [ rows - 3 , arx - 1 ] ,
317- [ rows - 2 , arx - 1 ] ,
318- [ rows - 6 , arx - 2 ] ,
319- [ rows - 5 , arx - 2 ] ,
320- [ rows - 4 , arx - 2 ] ,
321- [ rows - 3 , arx - 2 ] ,
322- [ rows - 2 , arx - 2 ] ,
323- [ rows - 6 , arx - 3 ] ,
324- [ rows - 5 , arx - 3 ] ,
325- [ rows - 4 , arx - 3 ] ,
326- [ rows - 3 , arx - 3 ] ,
327- [ rows - 2 , arx - 3 ] ,
328- [ rows - 6 , arx - 4 ] ,
329- [ rows - 5 , arx - 4 ] ,
330- [ rows - 4 , arx - 4 ] ,
331- ] ;
332- for ( let i = 0 ; i < 18 && i < rightPos . length ; i ++ ) {
333- const [ r , c ] = rightPos [ i ] ! ;
334- if ( r >= 0 && r < rows && c >= 0 && c < cols ) {
335- matrix [ r ] ! [ c ] = ( ( formatInfo >> i ) & 1 ) === 1 ;
299+ matrix [ 1 ] ! [ 11 ] = ( ( leftFmt >> 15 ) & 1 ) === 1 ;
300+ matrix [ 2 ] ! [ 11 ] = ( ( leftFmt >> 16 ) & 1 ) === 1 ;
301+ matrix [ 3 ] ! [ 11 ] = ( ( leftFmt >> 17 ) & 1 ) === 1 ;
302+
303+ // Right format info: rows (rows-6)-(rows-2), cols (cols-8)-(cols-6), + 3 extra
304+ for ( let i = 0 ; i < 5 ; i ++ ) {
305+ for ( let j = 0 ; j < 3 ; j ++ ) {
306+ matrix [ i + rows - 6 ] ! [ j + cols - 8 ] = ( ( rightFmt >> ( j * 5 + i ) ) & 1 ) === 1 ;
336307 }
337308 }
309+ matrix [ rows - 6 ] ! [ cols - 5 ] = ( ( rightFmt >> 15 ) & 1 ) === 1 ;
310+ matrix [ rows - 6 ] ! [ cols - 4 ] = ( ( rightFmt >> 16 ) & 1 ) === 1 ;
311+ matrix [ rows - 6 ] ! [ cols - 3 ] = ( ( rightFmt >> 17 ) & 1 ) === 1 ;
338312
339313 // 6. Place data bits (column-pair zigzag, skip timing columns)
340314 const allBits : number [ ] = [ ] ;
0 commit comments