Coverage report: /home/ellis/comp/core/lib/dat/qrcode.lisp
Kind | Covered | All | % |
expression | 82 | 3050 | 2.7 |
branch | 4 | 250 | 1.6 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; dat/qrcode.lisp --- QR Code formats
3
;; see https://github.com/jnjcc/cl-qrencode
5
;; Copyright (c) 2011-2014 jnjcc, Yste.org. All rights reserved.
8
(in-package :dat/qrcode)
11
(defun read-file-content (fpath)
12
(with-open-file (fp fpath)
13
(let ((content (make-string (file-length fp))))
14
(read-sequence content fp)
17
;;;; Galois Field with primitive element 2, as used by Reed-Solomon code
19
((power :initform nil :initarg :power :reader gf-power
20
:documentation "Galois Field GF(2^POWER)")
21
(prime-poly :initform nil :initarg :ppoly :reader prime-poly
22
:documentation "prime polynomial")
23
(order :initform nil :reader gf-order)
24
(exp-table :initform nil)
25
(log-table :initform nil)))
27
(defmethod initialize-instance :after ((gf galois) &rest args)
28
(declare (ignore args))
29
(setf (slot-value gf 'order) (ash 1 (slot-value gf 'power)))
30
(let* ((order (gf-order gf))
31
(ppoly (prime-poly gf))
32
;; 2^0 = 1 && (log 0) = -1
33
(exptab (make-array order :initial-element 1))
34
(logtab (make-array order :initial-element -1)))
37
(setf (aref exptab i) (* (aref exptab (- i 1)) 2))
38
(when (>= (aref exptab i) order)
40
(boole boole-and (- order 1)
41
(boole boole-xor (aref exptab i) ppoly))))
42
(setf (aref logtab (aref exptab i)) i))
43
(setf (aref logtab 1) 0)
44
(setf (slot-value gf 'exp-table) exptab)
45
(setf (slot-value gf 'log-table) logtab)))
48
(defgeneric gf-exp (gf pow)
49
(:documentation "2^POW under Galois Field GF"))
50
(defgeneric gf-log (gf value)
51
(:documentation "VALUE should be within range [0, 2^POW - 1]"))
53
(defmethod gf-exp ((gf galois) pow)
54
(let* ((sz (- (gf-order gf) 1))
56
(aref (slot-value gf 'exp-table) idx)))
58
(defmethod gf-log ((gf galois) value)
59
(let* ((sz (gf-order gf))
61
(aref (slot-value gf 'log-table) idx)))
63
;;; Galois Field arithmetic
64
(defgeneric gf-add (gf a b))
65
(defgeneric gf-subtract (gf a b))
66
(defgeneric gf-multiply (gf a b))
67
(defgeneric gf-divide (gf a b))
69
(defmethod gf-add ((gf galois) a b)
70
(boole boole-xor a b))
72
(defmethod gf-subtract ((gf galois) a b)
73
(boole boole-xor a b))
75
(defmethod gf-multiply ((gf galois) a b)
76
(let ((sum (+ (gf-log gf a) (gf-log gf b))))
79
(defmethod gf-divide ((gf galois) a b)
81
(error "divide by zero"))
84
(let ((sub (- (gf-log gf a) (gf-log gf b))))
87
;;; open-paren at beg of line confuses `slime-compile-defun` which uses
88
;;; elisp function `beginning-of-defun`, which in turn involves
89
;;; backward-searching open-paren at beg of line
90
;;; there seems to be no easy way to fix this problem
91
;; with an extra leading '\', docstring is kind of ulgy now, though
92
(defmacro with-gf-accessors (accessors gf &body body)
93
"shortcuts for gf-exp & gf-log, usage:
94
\(with-gf-accessors ((gfexp gf-exp)) *gf-instance* ...)"
95
`(labels ,(mapcar (lambda (acc-entry)
96
(let ((acc-name (car acc-entry))
97
(method-name (cadr acc-entry)))
99
(,method-name ,gf a))))
103
(defmacro with-gf-arithmetics (ariths gf &body body)
104
"shortcuts for gf-add, gf-subtract, gf-multiply & gf-divide, usage:
105
\(with-gf-arithmetics ((gf+ gf-add)) *gf-instance* ...)"
106
`(labels ,(mapcar (lambda (arith-entry)
107
(let ((arith-name (car arith-entry))
108
(method-name (cadr arith-entry)))
110
(,method-name ,gf a b))))
114
(defmacro with-gf-shortcuts (accessors ariths gf &body body)
115
"combined with-gf-accessors & with-gf-arithmetics, usage:
116
\(with-gf-shortcuts ((gflog gf-log)) ((gf* gf-multiply)) *gf-instance* ...)"
118
(mapcar (lambda (acc-entry)
119
(let ((acc-name (car acc-entry))
120
(method-name (cadr acc-entry)))
122
(,method-name ,gf a))))
124
(mapcar (lambda (arith-entry)
125
(let ((arith-name (car arith-entry))
126
(method-name (cadr arith-entry)))
128
(,method-name ,gf a b))))
132
;;;; Bose-Chaudhuri-Hocquenghem (BCH) error correction code
134
;;; Polynomial (using list) arithmetics
135
;;; by polynomial list (3 2 1), we mean 3*x^2 + 2*x + 1
136
(defun poly-ash (poly s)
137
"shift left POLY by S"
138
(declare (type list poly))
139
(append poly (make-list s :initial-element 0)))
140
(defun poly-multiply (poly b &optional (op #'*))
141
"multiply B on every element of POLY using OP"
142
(labels ((mult (elem)
143
(funcall op elem b)))
144
(mapcar #'mult poly)))
145
(defun poly-substract (lhs rhs &optional (op #'-))
146
(labels ((sub (elem1 elem2)
147
(funcall op elem1 elem2)))
148
(mapcar #'sub lhs rhs)))
149
(defun poly-mod (msg gen rem &optional (sub #'poly-substract) (mul #'poly-multiply))
150
"MSG % GEN, with REM remainders"
151
(labels ((cdrnzero (msg rem)
152
(do ((head msg (cdr head)))
153
((or (null head) (<= (length head) rem) (/= (car head) 0)) head)
155
(do ((m (poly-ash msg rem) (cdrnzero m rem)))
156
((<= (length m) rem) m)
157
(let* ((glen (length gen))
158
(sft (- (length m) glen))
159
;; LEAD coffiecient of message polynomial
161
(setf m (funcall sub m (poly-ash (funcall mul gen lead) sft)))))))
164
((k :initform nil :initarg :k
165
:documentation "# of data codewords")
166
(ec :initform nil :initarg :ec
167
:documentation "# of error correction codewords")))
170
(poly-multiply poly b))
171
(defun bch- (lhs rhs)
173
(boole boole-xor a b)))
174
(poly-substract lhs rhs #'xor)))
175
(defun bch-xor (lhs rhs)
177
(boole boole-xor a b)))
178
(mapcar #'xor lhs rhs)))
179
(defun bch% (msg gen rem)
180
(poly-mod msg gen rem #'bch- #'bch*))
182
(defgeneric bch-ecc (bch msgpoly genpoly)
183
(:documentation "do bch error correction under BCH(K+EC, K)"))
185
(defmethod bch-ecc ((bch bch-ecc) msg gen)
186
(with-slots (k ec) bch
187
(unless (= (length msg) k)
188
(error "wrong msg length, expect: ~A; got: ~A~%" k (length msg)))
191
;;; As used by format information ecc & version information ecc respectively
192
;;; BCH(15, 5) & BCH(18, 6)
193
(let ((fi-ecc (make-instance 'bch-ecc :k 5 :ec 10))
194
;; format information generator polynomial
195
;; x^10 + x^8 + x^5 + x^4 + x^2 + x + 1
196
(fi-gpoly '(1 0 1 0 0 1 1 0 1 1 1))
197
(fi-xor '(1 0 1 0 1 0 0 0 0 0 1 0 0 1 0)))
198
(defun format-ecc (level mask-ind)
199
(let ((seq (append (level-indicator level)
200
(mask-pattern-ref mask-ind))))
201
(bch-xor (append seq (bch-ecc fi-ecc seq fi-gpoly))
204
(let ((vi-ecc (make-instance 'bch-ecc :k 6 :ec 12))
205
;; version information generator polynomial
206
;; x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1
207
(vi-gpoly '(1 1 1 1 1 0 0 1 0 0 1 0 1)))
208
(defun version-ecc (version)
209
(let ((seq (decimal->bstream version 6)))
210
(append seq (bch-ecc vi-ecc seq vi-gpoly)))))
213
((k :initform nil :initarg :k
214
:documentation "# of data codewords")
215
(ec :initform nil :initarg :ec
216
:documentation "# of error correction codewords")
217
(gpoly :initform nil :reader gpoly
218
:documentation "with EC, we calculate generator poly immediately")))
220
;;; Reed-Solomon code uses GF(2^8) with prime polynomial 285,
221
;;; or 1,0001,1101, or (x^8 + x^4 + x^3 + x^2 + 1)
222
(let ((gf256 (make-instance 'galois :power 8 :ppoly 285)))
223
;; Polynomial arithmetics under GF(2^8), as used by Reed-Solomon ecc
225
"multiply B on every element of POLY under GF(2^8)"
226
(with-gf-arithmetics ((gf* gf-multiply)) gf256
227
(poly-multiply poly b #'gf*)))
229
(with-gf-arithmetics ((gf- gf-subtract)) gf256
230
(poly-substract lhs rhs #'gf-)))
231
(defun rs% (msg gen rem)
232
(poly-mod msg gen rem #'rs- #'rs*))
234
(defmethod initialize-instance :after ((rs rs-ecc) &rest args)
235
(declare (ignore args))
236
(setf (slot-value rs 'gpoly) (gen-poly rs)))
238
(defgeneric gen-poly (rs))
239
(defmethod gen-poly ((rs rs-ecc))
240
"Generator Polynomial: (x-a^0) * (x-a^1) * ... * (x-a^(ec-1))"
242
(let* ((size (+ ec 1))
243
(poly (make-list size :initial-element nil)))
244
(with-gf-shortcuts ((gfexp gf-exp)) ((gf+ gf-add) (gf* gf-multiply)) gf256
249
(setf (nth i poly) 1)
250
(do ((j (- i 1) (1- j)))
252
(if (not (= (nth j poly) 0))
254
(gf+ (nth (- j 1) poly)
255
(gf* (nth j poly) (gfexp (- i 1)))))
256
(setf (nth j poly) (nth (- j 1) poly))))
257
(setf (nth 0 poly) (gf* (nth 0 poly) (gfexp (- i 1))))))
260
(defgeneric gen-poly-gflog (rs))
261
(defgeneric ecc-poly (rs msg))
263
(defmethod gen-poly-gflog ((rs rs-ecc))
264
(with-gf-accessors ((gflog gf-log)) gf256
265
;; GPOLY already calculated when making new instance
266
(mapcar #'gflog (gpoly rs))))
268
(defmethod ecc-poly ((rs rs-ecc) msg-poly)
269
"Error Correction codewords Polynomial for MSG-POLY"
270
(with-slots (k ec gpoly) rs
271
(unless (= (length msg-poly) k)
272
(error "wrong msg-poly length, expect: ~A~%" k))
273
(rs% msg-poly gpoly ec))))
277
:numeric :alnum :byte :kanji
278
;; Extended Channel Interpretation, Structured Append, FNC1
279
:eci :structured :fnc1))
281
(defun mode-indicator (mode)
282
(declare (type qr-mode mode))
284
(:numeric '(0 0 0 1)) ; "0001"
285
(:alnum '(0 0 1 0)) ; "0010"
286
(:byte '(0 1 0 0)) ; "0100"
287
(:kanji '(1 0 0 0)) ; "1000"
288
(:eci '(0 1 1 1)) ; "0111"
289
(:structured '(0 0 1 1)) ; "0011"
290
(:fnc1 '(0 1 0 1)))) ; FIXME: "0101" & "1001"
292
(defun terminator (bstream version level)
294
(let* ((nbits (length bstream))
295
(diff (- (* (data-words-capacity version level) 8)
298
((< diff 0) (error "you serious about this?!"))
299
((<= diff 4) (make-list diff :initial-element 0))
300
(t (make-list 4 :initial-element 0)))))
302
(defun byte-value (mode byte)
303
"BYTE value under MODE"
304
(declare (type qr-mode mode))
307
(and (<= #x30 byte #x39)
311
((<= #x30 byte #x39) (- byte #x30)) ; 0-9
312
((<= #x41 byte #x5A) (+ (- byte #x41) 10)) ; A-Z
313
((= byte #x20) 36) ; SP
314
((= byte #x24) 37) ; $
315
((= byte #x25) 38) ; %
316
((= byte #x2A) 39) ; *
317
((= byte #x2B) 40) ; +
318
((= byte #x2D) 41) ; -
319
((= byte #x2E) 42) ; .
320
((= byte #x2F) 43) ; /
321
((= byte #x3A) 44) ; :
323
((:byte :kanji) byte)))
325
(defun kanji-word-p (word)
326
"(kanji-p, kanji-range: {0, 1})"
328
((<= #x8140 word #x9ffc) (values t 0))
329
((<= #xe040 word #xebbf) (values t 1))
330
(t (values nil nil))))
332
(defun starts-kanji-p (bytes)
333
"(BYTES starts with kanji-p, kanji word value, kanji-range: {0, 1})"
334
(declare (type list bytes))
335
(let* ((first (car bytes))
336
(second (cadr bytes))
337
(word (and second (+ (ash first 8) second))))
338
(if (and first second)
339
(multiple-value-bind (kanji-p range)
341
(values kanji-p word range))
342
(values nil nil nil))))
344
(defun xor-subset-of (bytes)
345
"exclusive subset of first unit of BYTES.
346
as for unit, one byte for :numeric, :alnum; two bytes for :kanji"
347
(declare (type list bytes))
348
(let* ((first (car bytes)))
350
((null first) :unknown)
351
((byte-value :numeric first) :numeric)
352
((byte-value :alnum first) :alnum)
353
;; excluding reserved values 80-9F & E0-FF
354
((and (not (<= #x80 first #x9F))
355
(not (<= #xE0 first #xFF)))
357
((starts-kanji-p bytes)
360
(defclass qr-input ()
362
:initform nil :initarg :bytes :reader bytes :type list
363
:documentation "list of bytes to be encoded")
365
:initform 1 :initarg :version :reader version
366
:documentation "version of qr symbol, adapted according to BYTES")
367
(ec-level ; cannot be NIL
368
:initform :level-m :initarg :ec-level :reader level :type ecc-level)
370
:initform nil :initarg :mode :reader mode :type (or null qr-mode)
371
:documentation "if supplied, we force all BYTES to be under MODE,
372
therefore, unless you know exactly what you are doing, leave this NIL")
374
:initform 0 :accessor cur-byte
375
:documentation "index of BYTES during data analysis")
377
:initform nil :accessor segments :type list
379
"list of list, of the form ((:mode1 byte ...) (:mode2 byte ...) ...)")
381
:initform nil :reader bstream :type list
382
:documentation "list of 0-1 values after encoding SEGMENTS")
384
:initform nil :reader blocks :type list
385
:documentation "list of list, of the form ((codeword ...) (codeword ...) ...)
386
after converting BSTREAM to codewords")
387
(ecc-blocks ; error correction blocks
388
:initform nil :reader ecc-blocks :type list
389
:documentation "list of list, ec codewords corresponding to BLOCKS")
391
:initform nil :reader message :type list
392
:documentation "list of codewords from BLOCKS & ECC-BLOCKS,
393
interleaving if neccessary")
395
:initform nil :accessor matrix
396
:documentation "raw QR code symbol (without masking) as matrix")))
398
(defmethod initialize-instance :after ((input qr-input) &rest args)
399
(declare (ignore args))
400
(validate-and-analysis input))
403
(defgeneric validate-and-analysis (input)
404
(:documentation "adapt VERSION according to BYTES, and fill SEGMENTS slot"))
406
(defgeneric data-encoding (input)
407
(:documentation "encode SEGMENTS into BSTREAM slot"))
408
;;; 2) Error correction coding
409
(defgeneric ec-coding (input)
410
(:documentation "split BSTREAM into BLOCKS, do rs-ecc, and fill ECC-BLOCKS"))
411
;;; 3) Structure final message
412
(defgeneric structure-message (input)
413
(:documentation "interleaving BLOCKS and ECC-BLOCKS into MSG-CODEWORDS"))
414
;;; 4) Codeword placement in matrix, a.k.a, raw QR code symbol
415
(defgeneric module-placement (input)
416
(:documentation "write MSG-CODEWORDS into the raw (without masking) MATRIX"))
417
;;; 5) Data masking & Format information
418
(defgeneric data-masking (input)
419
(:documentation "mask MATRIX with best pattern, generate the final symbol"))
421
(defgeneric data-analysis (input)
422
(:documentation "BYTES -> SEGMETS, switch bewteen modes as necessary to
423
achieve the most efficient conversion of data"))
424
(defgeneric redo-data-analysis (input)
425
(:documentation "VERSION changed, reset CUR-BYTE and redo data analysis"))
426
(defgeneric analyse-byte-mode (input &optional seg))
427
(defgeneric analyse-alnum-mode (input &optional seg))
428
(defgeneric analyse-numeric-mode (input &optional seg))
429
(defgeneric analyse-kanji-mode (input &optional seg))
430
(defgeneric append-cur-byte (input &optional seg)
431
(:documentation "append CUR-BYTE of BYTES into SEGMENTS"))
432
(defun mode-analyse-func (mode)
433
"put CUR-BYTE into MODE, and then look at following BYTES for new segment"
435
(:byte #'analyse-byte-mode)
436
(:alnum #'analyse-alnum-mode)
437
(:numeric #'analyse-numeric-mode)
438
(:kanji #'analyse-kanji-mode)))
440
(defmethod data-analysis ((input qr-input))
441
(with-slots (mode cur-byte segments) input
442
(when mode ; MODE supplied
443
(let ((seg (append (list mode) (bytes input))))
444
(setf cur-byte (length (bytes input)))
445
(setf segments (append segments (list seg))))
446
(return-from data-analysis)))
447
(with-slots (bytes version segments) input
448
(let ((init-mode (select-init-mode bytes version)))
449
(funcall (mode-analyse-func init-mode) input))))
451
(defmethod redo-data-analysis ((input qr-input))
452
(with-slots (cur-byte segments) input
455
(data-analysis input)))
457
(defun select-init-mode (bytes version)
458
"optimization of bitstream length: select initial mode"
459
(declare (type list bytes))
460
(let ((init-xor (xor-subset-of bytes)))
464
(case (xor-subset-of (nthcdr 2 bytes))
465
((:numeric :alnum) :kanji)
467
(let ((nunits (ecase (version-range version)
470
(if (every-unit-matches (nthcdr 3 bytes) 2 nunits :kanji)
475
(let ((nunits (ecase (version-range version)
477
;; number of units (characters) match :alnum, followed by a :byte unit
478
(multiple-value-bind (n last-mode) (nunits-matches (cdr bytes) :alnum)
479
(if (and (< n nunits) (eq last-mode :byte))
483
(let ((nbunits (ecase (version-range version)
485
(naunits (ecase (version-range version)
487
(multiple-value-bind (n last-mode) (nunits-matches (cdr bytes) :numeric)
488
(if (and (< n nbunits) (eq last-mode :byte))
490
(if (and (< n naunits) (eq last-mode :alnum))
494
;;; UNIT: character under a certain mode,
495
;;; a byte under :numeric :alnum & :byte, or a byte-pair under :kanji
496
(defun every-unit-matches (bytes usize nunits mode)
497
"if every unit of USZIE bytes (at most NUNITS unit) within BYTES matches MODE"
498
(declare (type list bytes) (type qr-mode mode))
499
(when (>= (length bytes) (* usize nunits))
501
(let ((b (nthcdr (* usize i) bytes)))
502
(unless (eq (xor-subset-of b) mode)
503
(return-from every-unit-matches nil))))
504
(return-from every-unit-matches t)))
506
(defun nunits-matches (bytes mode)
507
"(number of units that matches MODE, and mode for the first unmatched unit)"
508
(declare (type list bytes) (type qr-mode mode))
509
(let ((usize (ecase mode
510
((:byte :alnum :numeric) 1)
511
;; as for :kanji, 2 bytes forms a single unit
514
(do ((b bytes (nthcdr usize b)))
516
(not (eq (xor-subset-of b) mode)))
517
(values nunits (xor-subset-of b)))
520
(defmethod analyse-byte-mode ((input qr-input) &optional (seg '(:byte)))
521
(declare (type list seg))
522
(setf seg (append-cur-byte input seg))
524
(return-from analyse-byte-mode))
525
(with-slots (bytes cur-byte version segments) input
526
(let* ((range (version-range version))
527
(nkunits (ecase range ; number of :kanji units before more :byte
528
(0 9) (1 12) (2 13)))
529
(nanuits (ecase range ; number of :alnum units before more :byte
530
(0 11) (1 15) (2 16)))
531
(nmunits1 (ecase range ; number of :numeric units before more :byte
533
(nmunits2 (ecase range ; number of :numeric units before more :alnum
536
(multiple-value-bind (nmatches last-mode)
537
(nunits-matches (nthcdr cur-byte bytes) :kanji)
538
(and (>= nmatches nkunits) (eq last-mode :byte)
539
(setf switch-mode :kanji)))
541
(multiple-value-bind (nmatches last-mode)
542
(nunits-matches (nthcdr cur-byte bytes) :alnum)
543
(and (>= nmatches nanuits) (eq last-mode :byte)
544
(setf switch-mode :alnum))))
546
(multiple-value-bind (nmatches last-mode)
547
(nunits-matches (nthcdr cur-byte bytes) :numeric)
549
(:byte (and (>= nmatches nmunits1)
550
(setf switch-mode :numeric)))
551
(:alnum (and (>= nmatches nmunits2)
552
(setf switch-mode :numeric))))))
555
;; current segment finished, add a new SWITCH-MODE segment
556
(setf segments (append segments (list seg)))
557
(setf seg (list switch-mode)))
558
(setf switch-mode :byte))
559
(funcall (mode-analyse-func switch-mode) input seg))))
561
(defmethod analyse-alnum-mode ((input qr-input) &optional (seg '(:alnum)))
562
(declare (type list seg))
563
(setf seg (append-cur-byte input seg))
565
(return-from analyse-alnum-mode))
566
(with-slots (bytes cur-byte version segments) input
567
(let ((nmunits (ecase (version-range version)
568
(0 13) (1 15) (2 17)))
570
(when (>= (nunits-matches (nthcdr cur-byte bytes) :kanji) 1)
571
(setf switch-mode :kanji))
573
(when (>= (nunits-matches (nthcdr cur-byte bytes) :byte) 1)
574
(setf switch-mode :byte)))
576
(multiple-value-bind (nmatches last-mode)
577
(nunits-matches (nthcdr cur-byte bytes) :numeric)
578
(and (>= nmatches nmunits) (eq last-mode :alnum)
579
(setf switch-mode :numeric))))
582
(setf segments (append segments (list seg)))
583
(setf seg (list switch-mode)))
584
(setf switch-mode :alnum))
585
(funcall (mode-analyse-func switch-mode) input seg))))
587
(defmethod analyse-numeric-mode ((input qr-input) &optional (seg '(:numeric)))
588
(declare (type list seg))
589
(setf seg (append-cur-byte input seg))
591
(return-from analyse-numeric-mode))
592
(with-slots (bytes cur-byte version segments) input
593
(let ((switch-mode nil))
594
(when (>= (nunits-matches (nthcdr cur-byte bytes) :kanji) 1)
595
(setf switch-mode :kanji))
597
(when (>= (nunits-matches (nthcdr cur-byte bytes) :byte) 1)
598
(setf switch-mode :byte)))
600
(when (>= (nunits-matches (nthcdr cur-byte bytes) :alnum) 1)
601
(setf switch-mode :alnum)))
604
(setf segments (append segments (list seg)))
605
(setf seg (list switch-mode)))
606
(setf switch-mode :numeric))
607
(funcall (mode-analyse-func switch-mode) input seg))))
609
(defmethod append-cur-byte ((input qr-input) &optional seg)
610
"if CUR-BYTE is the last byte, return nil"
611
(declare (type list seg))
612
(with-slots (bytes cur-byte segments) input
613
(setf seg (append seg (list (nth cur-byte bytes))))
615
(when (>= cur-byte (length bytes))
616
(setf segments (append segments (list seg)))
618
(return-from append-cur-byte seg)))
620
(defmethod analyse-kanji-mode ((input qr-input) &optional (seg '(:kanji)))
621
(declare (type list seg))
622
(with-slots (bytes cur-byte segments) input
623
(setf seg (append seg (nthcdr cur-byte bytes)))
624
(setf cur-byte (length bytes))
625
(setf segments (append segments (list seg)))))
627
(defmethod validate-and-analysis ((input qr-input))
628
(with-slots ((level ec-level) segments) input
629
(unless (<= 1 (version input) 40)
630
(error "version ~A out of bounds" (version input)))
632
((<= (version input) prev))
633
(setf prev (version input))
634
(redo-data-analysis input)
635
(labels ((seg-bstream-len (seg)
636
(segment-bstream-length seg (version input))))
637
(let* ((blen (reduce #'+ (mapcar #'seg-bstream-len segments)
639
(min-v (minimum-version prev (ceiling blen 8) level)))
641
(setf (slot-value input 'version) min-v)
642
(error "no version to hold ~A bytes" (ceiling blen 8))))))))
644
(defmethod data-encoding ((input qr-input))
645
(with-slots (version (level ec-level) segments) input
646
(labels ((seg->bstream (seg)
647
(segment->bstream seg version)))
648
(let* ((bs (reduce #'append (mapcar #'seg->bstream segments)
650
(tt (terminator bs version level))
651
;; connect bit streams in all segment, with terminator appended
652
(bstream (append bs tt)))
654
(setf bstream (append bstream (padding-bits bstream)))
655
;; add pad codewords, finishes data encoding
656
(setf (slot-value input 'bstream)
658
(pad-codewords bstream version level)))))))
660
(defmethod ec-coding ((input qr-input))
661
(with-slots (version (level ec-level) bstream) input
662
(let ((codewords (bstream->codewords bstream))
665
;; RS error correction obj for blk1 & blk2
668
(multiple-value-bind (ecc-num blk1 data1 blk2 data2)
669
(ecc-block-nums version level)
671
(setf rs1 (make-instance 'rs-ecc :k data1 :ec ecc-num)))
673
(setf rs2 (make-instance 'rs-ecc :k data2 :ec ecc-num)))
676
(append blocks (list (subseq codewords 0 data1))))
677
(setf codewords (nthcdr data1 codewords)))
680
(append blocks (list (subseq codewords 0 data2))))
681
(setf codewords (nthcdr data2 codewords)))
684
(append ecc-blocks (list (ecc-poly rs1 (nth i blocks))))))
687
(append ecc-blocks (list (ecc-poly rs2 (nth (+ i blk1) blocks))))))
688
(setf (slot-value input 'blocks) blocks)
689
(setf (slot-value input 'ecc-blocks) ecc-blocks)))))
691
(defmethod structure-message ((input qr-input))
692
(with-slots (version (level ec-level) blocks ecc-blocks) input
694
(multiple-value-bind (ecc-num blk1 data1 blk2 data2)
695
(ecc-block-nums version level)
696
(declare (ignore ecc-num))
697
(setf (slot-value input 'msg-codewords)
699
;; interleave data blocks, data blocks may differ in length
700
(take-data-in-turn blocks blk1 data1 blk2 data2)
701
;; we know error correction blocks are of the same length
702
(take-in-turn ecc-blocks)))))))
704
(defmethod module-placement ((input qr-input))
705
(setf (matrix input) (make-matrix (version input)))
706
(with-slots (version msg-codewords matrix) input
707
;; Function pattern placement
708
(function-patterns matrix version)
709
;; Symbol character placement
710
(let ((rbits (remainder-bits version))
712
(labels ((dec->byte (codeword)
713
(decimal->bstream codeword 8)))
714
(setf bstream (append (reduce #'append (mapcar #'dec->byte msg-codewords))
715
;; data capacity of _symbol_ does not divide by 8
716
(make-list rbits :initial-element 0))))
717
(symbol-character bstream matrix version))))
719
(defmethod data-masking ((input qr-input))
720
"(masked matrix, mask pattern reference)"
721
(with-slots (version (level ec-level) matrix) input
722
(let ((modules (matrix-modules version)))
723
(multiple-value-bind (masked indicator)
724
(choose-masking matrix modules level)
725
(values masked (mask-pattern-ref indicator))))))
727
(defun decimal->bstream (dec nbits)
728
"using NBITS bits to encode decimal DEC"
735
(defun bstream->decimal (bstream nbits)
736
(declare (type list bstream))
737
(let ((nbits (min nbits (length bstream)))
740
(setf dec (+ (* dec 2) (nth i bstream))))
744
(defun group->decimal (values ndigits)
745
"digit groups of length NDIGITS (1, 2 or 3) to decimal"
746
(declare (type list values))
749
(2 (+ (* (nth 0 values) 10) (nth 1 values)))
750
(3 (+ (* (nth 0 values) 100) (* (nth 1 values) 10) (nth 2 values)))))
751
(defun final-digit-bits (n)
752
"the final one or two digits are converted to 4 or 7 bits respectively"
755
(defun numeric->bstream (bytes)
756
(declare (type list bytes))
757
(labels ((num-value (byte)
758
(byte-value :numeric byte)))
759
(let ((values (mapcar #'num-value bytes))
761
(do ((v values (nthcdr 3 v)))
764
(1 ; only 1 digits left
766
(append bstream (decimal->bstream (group->decimal v 1)
767
(final-digit-bits 1)))))
768
(2 ; only 2 digits left
770
(append bstream (decimal->bstream (group->decimal v 2)
771
(final-digit-bits 2)))))
772
(otherwise ; at least 3 digits left
775
(decimal->bstream (group->decimal v 3) 10)))))))))
778
(defun pair->decimal (values num)
779
"alnum pairs of length NUM (1 or 2) to decimal"
780
(declare (type list values))
783
(2 (+ (* (nth 0 values) 45) (nth 1 values)))))
784
(defun alnum->bstream (bytes)
785
(declare (type list bytes))
786
(labels ((alnum-value (byte)
787
(byte-value :alnum byte)))
788
(let ((values (mapcar #'alnum-value bytes))
790
(do ((v values (nthcdr 2 v)))
793
(1 ; only 1 alnum left
796
(decimal->bstream (pair->decimal v 1) 6))))
797
(otherwise ; at least 2 alnum left
800
(decimal->bstream (pair->decimal v 2) 11)))))))))
803
(defun byte->bstream (bytes)
804
(declare (type list bytes))
805
(labels ((join (prev cur)
806
(append prev (decimal->bstream (byte-value :byte cur) 8))))
807
(reduce #'join bytes :initial-value nil)))
810
(defun kanji->decimal (word range)
811
(let ((subtractor (ecase range
814
(decf word subtractor)
815
(setf word (+ (* (ash word -8) #xc0)
816
(boole boole-and word #xff)))))
817
(defun kanji->bstream (bytes)
818
(declare (type list bytes))
819
(labels ((kanji-value (byte)
820
(byte-value :kanji byte)))
821
(let ((values (mapcar #'kanji-value bytes))
824
(do ((v values (nthcdr delta v)))
827
(1 ; only 1 byte left
829
(append bstream (decimal->bstream (car v) 13)))
831
(otherwise ; at least 2 bytes left
832
(multiple-value-bind (kanji-p word range) (starts-kanji-p v)
837
(decimal->bstream (kanji->decimal word range)
842
(append bstream (decimal->bstream (car v) 13)))
843
(setf delta 1))))))))))
846
(defun eci->bstream (bytes)
848
(declare (ignore bytes))
849
(error "eci->bstream: TODO..."))
851
(defun bstream-trans-func (mode)
853
(:numeric #'numeric->bstream)
854
(:alnum #'alnum->bstream)
855
(:byte #'byte->bstream)
856
(:kanji #'kanji->bstream)))
858
(defun kanji-bytes-length (bytes)
859
(declare (type list bytes))
862
(do ((b bytes (nthcdr step b)))
864
(if (starts-kanji-p b)
869
(defun bytes-length (bytes mode)
870
"number of data characters under MODE"
871
(declare (type list bytes) (type qr-mode mode))
873
((:numeric :alnum :byte) (length bytes))
874
(:kanji (kanji-bytes-length bytes))))
876
(defun segment-bstream-length (segment version)
877
"bit stream length of SEGMENT (:mode b0 b1 ...) under VERSION"
878
(declare (type list segment))
879
(let* ((mode (car segment))
880
(bytes (cdr segment))
882
(c (char-count-bits version mode))
883
(d (bytes-length bytes mode))
885
;; M = number of bits in mode indicator
886
;; C = number of bits in character count indicator
887
;; D = number of input data characters
890
(setf r (final-digit-bits (mod d 3)))
891
;; B = M + C + 10 * (D / 3) + R
892
(+ m c (* 10 (floor d 3)) r))
895
;; B = M + C + 11 * (D / 2) + 6 * (D % 2)
896
(+ m c (* 11 (floor d 2)) (* 6 r)))
901
;; B = M + C + 13 * D
904
(defun segment->bstream (segment version)
905
"SEGMENT (:mode b0 b1 ...) to bit stream under VERSION"
906
(declare (type list segment))
907
(let* ((mode (car segment))
908
(bytes (cdr segment))
909
(len (bytes-length bytes mode))
910
(n (char-count-bits version mode))
912
(append bstream (mode-indicator mode)
913
(decimal->bstream len n) ; character count indicator
914
(funcall (bstream-trans-func mode) bytes))))
916
(defun padding-bits (bstream)
917
"add padding bits so that BSTREAM ends at a codeword boundary"
918
(multiple-value-bind (quot rem) (ceiling (length bstream) 8)
919
(declare (ignore quot))
920
(make-list (- rem) :initial-element 0)))
922
(defun pad-codewords (bstream version level)
923
"add pad codewords (after adding padding-bits) to fill data codeword capacity"
924
(let ((pad-words '((1 1 1 0 1 1 0 0)
926
(pad-len (- (data-words-capacity version level)
927
(/ (length bstream) 8)))
930
(setf ret (append ret (nth (mod i 2) pad-words))))
933
(defun bstream->codewords (bstream)
934
"convert bstream into codewords, as coefficients of the terms of a polynomial"
935
(do ((b bstream (nthcdr 8 b))
938
(setf codewords (append codewords (list (bstream->decimal b 8))))))
940
(defun take-in-turn (blks)
941
"taking codewords from each block (bound by minimum length) in turn"
942
(reduce #'append (apply #'mapcar #'list blks)))
944
(defun take-data-in-turn (blocks blk1 data1 blk2 data2)
945
"taking data words from each block (might have different length) in turn"
946
(let ((data-final nil)
948
(setf data-final (take-in-turn blocks))
950
((or (= blk1 0) (= blk2 0))
951
;; only one kind of block exists
952
(setf left-blks nil))
954
;; block 1 has more elements left
955
(setf left-blks (mapcar #'(lambda (blk)
957
(subseq blocks 0 blk1))))
959
;; block 2 has more elements left
960
(setf left-blks (mapcar #'(lambda (blk)
962
(subseq blocks blk1 (+ blk1 blk2))))))
964
(append data-final (take-in-turn left-blks))
967
(deftype module-color ()
968
":RAW, nothing has been done to this module; :RESERVE, format info reserve module
969
:FLIGHT/:FDARK, function pattern light/dark module; :LIGHT/:DARK, data modules"
970
'(member :raw :flight :fdark :reserve :light :dark))
972
(defun same-color-p (color1 color2)
973
"during QR symbol evaluation, :fdark & :dark are considered to be same"
975
((:flight :light) (or (eq color2 :flight) (eq color2 :light)))
976
((:fdark :dark) (or (eq color2 :fdark) (eq color2 :fdark)))
977
(otherwise (eq color1 color2))))
979
(defun raw-module-p (matrix i j)
980
"nothing has been done to MATRIX[I, J]"
981
(eq (aref matrix i j) :raw))
983
(defun make-modules-matrix (modules &optional (init :raw))
984
"make a raw matrix with MODULES * MODULES elements"
985
(make-array `(,modules ,modules) :initial-element init))
987
(defun make-matrix (version &optional (init :raw))
988
"make a raw matrix according to VERSION"
989
(let ((n (matrix-modules version)))
990
(make-modules-matrix n init)))
992
(defun paint-square (matrix x y n &optional (color :fdark))
993
"Paint a square of size N*N starting from upleft (X, Y) in MATRIX to COLOR"
994
(let ((maxx (+ x n -1))
996
(loop for i from x to maxx do
997
(loop for j from y to maxy do
998
(setf (aref matrix i j) color))))
1001
;;; Function Patterns
1002
(defun function-patterns (matrix version)
1003
(let ((modules (matrix-modules version)))
1004
(finder-patterns matrix modules)
1005
(separator matrix modules)
1006
(timing-patterns matrix modules)
1007
(alignment-patterns matrix version))
1009
;; a) Finder Patterns: fixed position in matrix
1010
(defun one-finder-pattern (matrix x y)
1011
"Paint one finder pattern starting from upleft (X, Y)"
1012
(paint-square matrix x y 7 :fdark)
1013
(paint-square matrix (+ x 1) (+ y 1) 5 :flight)
1014
(paint-square matrix (+ x 2) (+ y 2) 3 :fdark))
1015
(defun finder-patterns (matrix modules)
1016
;; top-left finder pattern
1017
(one-finder-pattern matrix 0 0)
1018
;; top-right finder pattern
1019
(one-finder-pattern matrix (- modules 7) 0)
1020
;; bottom-left finder pattern
1021
(one-finder-pattern matrix 0 (- modules 7)))
1023
;; b) Separator: fixed position in matrix
1024
(defun separator (matrix modules)
1026
;; top-left horizontal separator
1027
(setf (aref matrix 7 j) :flight)
1028
;; top-right horizontal separator
1029
(setf (aref matrix 7 (- modules j 1)) :flight)
1030
;; bottom-left horizontal separator
1031
(setf (aref matrix (- modules 8) j) :flight))
1033
;; top-left vertical separator
1034
(setf (aref matrix i 7) :flight)
1035
;; bottom-left vertical separator
1036
(setf (aref matrix (- modules i 1) 7) :flight)
1037
;; top-right vertical separator
1038
(setf (aref matrix i (- modules 8)) :flight))
1041
;; c) Timing patterns
1042
(defun timing-patterns (matrix modules)
1043
(let ((color :fdark))
1044
(loop for idx from 8 to (- modules 9) do
1047
(setf color :flight))
1049
(setf (aref matrix 6 idx) color)
1051
(setf (aref matrix idx 6) color)))
1054
;; d) Alignment Patterns: varies between versions
1055
;; may overlap timing patterns, modules coincide with that of timing patterns
1056
(defun one-align-pattern (matrix x y)
1057
"Paint one alignment pattern centered at (X, Y)"
1058
(paint-square matrix (- x 2) (- y 2) 5 :fdark)
1059
(paint-square matrix (- x 1) (- y 1) 3 :flight)
1060
(paint-square matrix x y 1 :fdark))
1061
(defun alignment-patterns (matrix version)
1062
(dolist (center (align-centers version) matrix)
1063
(one-align-pattern matrix (first center) (second center))))
1066
(defun symbol-character (bstream matrix version)
1067
(let ((modules (matrix-modules version)))
1068
(reserve-information matrix version)
1069
(bstream-placement bstream matrix modules))
1071
;; reserve format information & version information
1072
(defun reserve-information (matrix version)
1073
(let ((modules (matrix-modules version)))
1074
;; format information...
1075
;; top-left & top-right horizontal
1077
(when (raw-module-p matrix 8 j)
1078
(setf (aref matrix 8 j) :reserve))
1079
(setf (aref matrix 8 (- modules j 1)) :reserve))
1080
(setf (aref matrix 8 8) :reserve)
1081
;; top-left & bottom-left vertical
1083
(when (raw-module-p matrix i 8)
1084
(setf (aref matrix i 8) :reserve))
1085
(setf (aref matrix (- modules i 1) 8) :reserve))
1087
(setf (aref matrix (- modules 8) 8) :fdark)
1089
;; version information for version 7-40
1090
(when (>= version 7)
1091
(version-information matrix modules version))))
1093
(defun paint-fcolor-bit (matrix i j bit)
1094
"Paint function pattern color for MATRIX[I, J] according to BIT of {0, 1}"
1095
(setf (aref matrix i j) (case bit
1096
(0 :flight) (1 :fdark))))
1097
(defun version-information (matrix modules version)
1098
"version information placement on two blocks of modules:
1099
bottom-left 3*6 block: [modules-11, modules-9] * [0, 5]
1100
top-right 6*3 block: [0, 5] * [modules-11, modules-9]"
1101
(assert (>= version 7))
1102
(let ((vib (version-ecc version))
1104
(start (- modules 9))
1105
(bound (- modules 11))
1107
(dolist (bit vib matrix)
1108
(paint-fcolor-bit matrix i j bit)
1109
(paint-fcolor-bit matrix j i bit)
1110
(if (>= (- i 1) bound)
1116
;; Symbol character placement
1117
(defun paint-color-bit (matrix i j bit)
1118
"Paint data color for MATRIX[I, J] according to BIT of {0, 1}"
1119
(setf (aref matrix i j) (case bit
1120
(0 :light) (1 :dark))))
1121
(defun bstream-placement (bstream matrix modules)
1122
"2X4 module block for a regular symbol character. Regard the interleaved
1123
codeword sequence as a single bit stream, which is placed in the two module
1124
wide columns, alternately in the right and left modules, moving upwards or
1125
downwards according to DIRECTION, skipping function patterns, changing DIRECTION
1126
at the top or bottom of the symbol. The only exception is that no block should
1127
ever overlap the vertical timing pattern."
1128
(let ((i (- modules 1))
1130
;; -1: upwards, +1: downwards
1132
(len (length bstream)))
1134
((>= idx len) matrix)
1135
(when (raw-module-p matrix i j)
1136
(paint-color-bit matrix i j (nth idx bstream))
1138
(when (and (>= (- j 1) 0)
1139
(raw-module-p matrix i (- j 1)))
1141
(paint-color-bit matrix i (- j 1) (nth idx bstream))
1143
(if (< -1 (+ i direction) modules)
1146
;; reverse direction
1147
(setf direction (- direction))
1149
;; vertical timing pattern reached, the next block starts
1150
;; to the left of it
1154
;;; format information, during and after masking
1155
(defun format-information (matrix modules level mask-ind)
1156
;; format information bistream
1157
(let ((fib (format-ecc level mask-ind))
1161
(setf darks (count-if #'(lambda (elem) (= elem 1)) fib))
1162
;; horizontal 14 ~ 8
1163
(loop for j from 0 to 7 do
1164
(when (eq (aref matrix 8 j) :reserve)
1165
(paint-fcolor-bit matrix 8 j (nth idx fib))
1168
(loop for i from (- modules 1) downto (- modules 7) do
1169
(paint-fcolor-bit matrix i 8 (nth idx2 fib))
1172
(loop for j from (- modules 8) to (- modules 1) do
1173
(paint-fcolor-bit matrix 8 j (nth idx fib))
1176
(loop for i from 8 downto 0 do
1177
(when (eq (aref matrix i 8) :reserve)
1178
(paint-fcolor-bit matrix i 8 (nth idx2 fib))
1180
(values matrix darks)))
1182
;;; only encoding region modules (excluding format information) are masked
1183
(defun encoding-module-p (matrix i j)
1184
"modules belong to encoding region, excluding format & version information"
1185
(or (eq (aref matrix i j) :light)
1186
(eq (aref matrix i j) :dark)))
1187
(defun non-mask-module-p (matrix i j)
1188
(not (encoding-module-p matrix i j)))
1189
(defun reverse-module-color (matrix i j)
1190
(case (aref matrix i j)
1191
(:dark :light) (:light :dark)))
1193
;;; all modules are evaluated:
1194
;;; there should be only :dark :light :fdark :flight modules left by now
1195
(defun dark-module-p (matrix i j)
1196
(or (eq (aref matrix i j) :fdark)
1197
(eq (aref matrix i j) :dark)))
1199
(defun copy-and-mask (matrix modules level mask-ind)
1200
"make a new matrix and mask using MASK-IND for later evaluation"
1201
(let ((ret (make-modules-matrix modules))
1202
(mask-p (mask-condition mask-ind))
1204
(dotimes (i modules)
1205
(dotimes (j modules)
1207
((non-mask-module-p matrix i j)
1208
(setf (aref ret i j) (aref matrix i j)))
1209
((funcall mask-p i j) ; need mask
1210
(setf (aref ret i j) (reverse-module-color matrix i j)))
1212
(setf (aref ret i j) (aref matrix i j))))
1213
(when (dark-module-p ret i j)
1215
(multiple-value-bind (dummy fi-darks)
1216
(format-information ret modules level mask-ind)
1217
(declare (ignore dummy))
1218
;; add format information dark modules
1219
(values ret (+ darks fi-darks)))))
1221
(defun mask-matrix (matrix modules level mask-ind)
1222
"do not evaluate, just go ahead and mask MATRIX using MASK-IND mask pattern"
1223
(let ((mask-p (mask-condition mask-ind)))
1224
(dotimes (i modules)
1225
(dotimes (j modules)
1226
(and (encoding-module-p matrix i j)
1227
(funcall mask-p i j)
1228
(setf (aref matrix i j) (reverse-module-color matrix i j)))))
1229
;; paint format information
1230
(format-information matrix modules level mask-ind)
1233
(defvar *mask-pattern-num* 8)
1235
(defun choose-masking (matrix modules level)
1236
"mask and evaluate using each mask pattern, choose the best mask result"
1239
(mask-indicator nil)
1241
(square (* modules modules))
1243
(dotimes (i *mask-pattern-num*)
1244
(multiple-value-bind (cur-matrix darks)
1245
(copy-and-mask matrix modules level i)
1246
;; feature 4: proportion of dark modules in entire symbol
1247
(let ((bratio (/ (+ (* darks 200) square) square 2)))
1248
(setf cur-penalty (* (/ (abs (- bratio 50)) 5) n4)))
1249
(incf cur-penalty (evaluate-feature-123 cur-matrix modules))
1250
(when (or (null min-penalty)
1251
(< cur-penalty min-penalty))
1252
(setf min-penalty cur-penalty
1254
best-matrix cur-matrix))))
1255
(values best-matrix mask-indicator)))
1257
;;; feature 1 & 2 & 3
1258
(defun evaluate-feature-123 (matrix modules)
1260
(incf penalty (evaluate-feature-2 matrix modules))
1261
(dotimes (col modules)
1262
(let ((rlength (calc-run-length matrix modules col)))
1263
(incf penalty (evaluate-feature-1 rlength))
1264
(incf penalty (evaluate-feature-3 rlength))))
1265
(dotimes (row modules)
1266
(let ((rlength (calc-run-length matrix modules row :col)))
1267
(incf penalty (evaluate-feature-1 rlength))
1268
(incf penalty (evaluate-feature-3 rlength))))
1271
(defun calc-run-length (matrix modules num &optional (direction :row))
1272
"list of number of adjacent modules in same color"
1275
(labels ((get-elem (idx)
1277
(:row (aref matrix num idx))
1278
(:col (aref matrix idx num))))
1279
(add-to-list (list elem)
1280
(append list (list elem))))
1281
;; we make sure (NTH 1 rlength) is for dark module
1282
(when (same-color-p (get-elem 0) :dark)
1283
(setf rlength (add-to-list rlength -1)
1285
(setf rlength (add-to-list rlength 1))
1287
(loop for i from 1 to (- modules 1) do
1288
(if (same-color-p (get-elem i) (get-elem (- i 1)))
1289
(incf (nth ridx rlength))
1292
(setf rlength (add-to-list rlength 1)))))
1295
(defun evaluate-feature-1 (rlength)
1296
"(5 + i) adjacent modules in row/column in same color. (N1 + i) points, N1 = 3"
1299
(dolist (sz rlength penalty)
1301
(incf penalty (+ n1 sz -5))))))
1303
(defun evaluate-feature-3 (rlength)
1304
"1:1:3:1:1 ration (dark:light:dark:light:dark) pattern in row/column,
1305
preceded or followed by light area 4 modules wide. N3 points, N3 = 40"
1307
(len (length rlength))
1310
((>= i (- len 2)) penalty)
1311
(when (and (= (mod i 2) 1) ; for dark module
1312
(= (mod (nth i rlength) 3) 0)
1313
(let ((fact (floor (nth i rlength) 3)))
1316
(nth (- i 2) rlength)
1317
(nth (- i 1) rlength)
1318
(nth (+ i 1) rlength)
1319
(nth (+ i 2) rlength))
1321
((<= (- i 3) 0) (incf penalty n3))
1322
((>= (+ i 4) len) (incf penalty n3))
1323
((>= (nth (- i 3) rlength) (* 4 fact)) (incf penalty n3))
1324
((>= (nth (+ i 3) rlength) (* 4 fact)) (incf penalty n3))))))))))
1326
(defun evaluate-feature-2 (matrix modules)
1327
"block m * n of modules in same color. N2 * (m-1) * (n-1) points, N2=3"
1331
(dotimes (i (- modules 1) penalty)
1332
(dotimes (j (- modules 1))
1333
(when (dark-module-p matrix i j)
1335
(when (dark-module-p matrix (+ i 1) j)
1337
(when (dark-module-p matrix i (+ j 1))
1339
(when (dark-module-p matrix (+ i 1) (+ j 1))
1341
(when (or (= bcount 0) (= bcount 4))
1342
(incf penalty n2))))))
1344
(defclass qr-symbol ()
1345
((matrix :initform nil :initarg :matrix :reader matrix
1346
:documentation "qr code symbol as matrix")
1347
(modules :initform nil :initarg :modules :reader modules
1348
:documentation "qr code symbol modules")))
1350
(defmethod print-object ((symbol qr-symbol) stream)
1352
(with-slots (matrix modules) symbol
1353
(format stream "qr symbol ~A x ~A:~%" modules modules)
1354
(dotimes (i modules)
1355
(dotimes (j modules)
1356
(if (dark-module-p matrix i j)
1357
(format stream "1 ")
1358
(format stream "0 ")))
1359
(format stream "~%"))))
1361
;;; FIXME: other encodings???
1362
(defun ascii->bytes (text)
1363
(map 'list #'char-code text))
1365
(defun bytes->input (bytes version level mode)
1366
(setf version (min (max version 1) 40))
1367
(let ((input (make-instance 'qr-input :bytes bytes :version version
1368
:ec-level level :mode mode)))
1369
(data-encoding input)
1371
(structure-message input)
1372
(module-placement input)
1375
(defun input->symbol (input)
1376
"encode qr symbol from a qr-input"
1377
(multiple-value-bind (matrix mask-ref)
1378
(data-masking input)
1379
(declare (ignore mask-ref))
1380
(let ((modules (matrix-modules (version input))))
1381
(make-instance 'qr-symbol :matrix matrix :modules modules))))
1383
(defun encode-symbol-bytes (bytes &key (version 1) (level :level-m) (mode nil))
1384
"encode final qr symbol from BYTES list"
1385
(let ((input (bytes->input bytes version level mode)))
1386
(log:debug! (format nil "version: ~A; segments: ~A~%" (version input)
1388
(input->symbol input)))
1390
;;;-----------------------------------------------------------------------------
1391
;;; One Ring to Rule Them All, One Ring to Find Them,
1392
;;; One Ring to Bring Them All and In the Darkness Blind Them:
1393
;;; This function wraps all we need.
1394
;;;-----------------------------------------------------------------------------
1395
;; (sdebug :dbg-input)
1396
(defun encode-symbol (text &key (version 1) (level :level-m) (mode nil))
1397
"encode final qr symbol, unless you know what you are doing, leave MODE NIL"
1398
(let ((bytes (ascii->bytes text)))
1399
(encode-symbol-bytes bytes :version version :level level :mode mode)))
1401
;;; Table 1 - Codeword capacity of all versions of QR Code 2005
1402
;;; excluding Micro QR Code, varies between version
1403
(defvar *codeword-capacity-table*
1404
#2A((-1 -1 -1 -1 -1 -1) ; 0, no such version
1405
(21 202 31 208 26 0) (25 235 31 359 44 7)
1406
(29 243 31 567 70 7) (33 251 31 807 100 7)
1407
(37 259 31 1079 134 7) (41 267 31 1383 172 7)
1408
(45 390 67 1568 196 0) (49 398 67 1936 242 0)
1409
(53 406 67 2336 292 0) (57 414 67 2768 346 0) ; Version 10
1410
(61 422 67 3232 404 0) (65 430 67 3728 466 0)
1411
(69 438 67 4256 532 0) (73 611 67 4651 581 3)
1412
(77 619 67 5243 655 3) (81 627 67 5867 733 3)
1413
(85 635 67 6523 815 3) (89 643 67 7211 901 3)
1414
(93 651 67 7931 991 3) (97 659 67 8683 1085 3) ; Version 20
1415
(101 882 67 9252 1156 4) (105 890 67 10068 1258 4)
1416
(109 898 67 10916 1364 4) (113 906 67 11796 1474 4)
1417
(117 914 67 12708 1588 4) (121 922 67 13652 1706 4)
1418
(125 930 67 14628 1828 4) (129 1203 67 15371 1921 3)
1419
(133 1211 67 16411 2051 3) (137 1219 67 17483 2185 3) ; Version 30
1420
(141 1227 67 18587 2323 3) (145 1235 67 19723 2465 3)
1421
(149 1243 67 20891 2611 3) (153 1251 67 22091 2761 3)
1422
(157 1574 67 23008 2876 0) (161 1582 67 24272 3034 0)
1423
(165 1590 67 25568 3196 0) (169 1598 67 26896 3362 0)
1424
(173 1606 67 28256 3532 0) (177 1614 67 29648 3706 0)) ; Version 40
1425
"Number of modules (as version increases, 4 modules added) A | Function pattern
1426
modules B | Format and Version information modules C | Data modules (A^2-B-C) |
1427
Data capacity codewords (bytes, including ecc codewords) | Remainder bits.")
1428
(defun codeword-capacity (version)
1429
"codeword: data word + ecc word"
1430
(aref *codeword-capacity-table* version 4))
1431
(defun matrix-modules (version)
1432
(aref *codeword-capacity-table* version 0))
1433
(defun remainder-bits (version)
1434
(aref *codeword-capacity-table* version 5))
1436
(defun mode->index (mode)
1443
(deftype ecc-level ()
1444
'(member :level-l :level-m :level-q :level-h))
1445
(defun level->index (level)
1452
;;; (Part I of) Table 9 - Number of Error Correction Codewords (bytes)
1453
;;; varies between version and level
1454
(defvar *ecc-codewords-table*
1455
;; (:level-l :level-m :level-q :level-h)
1456
#2A((-1 -1 -1 -1) ;; 0, no such version
1457
(7 10 13 17) (10 16 22 28) (15 26 36 44)
1458
(20 36 52 64) (26 48 72 88) (36 64 96 112)
1459
(40 72 108 130) (48 88 132 156) (60 110 160 192)
1460
(72 130 192 224) (80 150 224 264) (96 176 260 308)
1461
(104 198 288 352) (120 216 320 384) (132 240 360 432)
1462
(144 280 408 480) (168 308 448 532) (180 338 504 588)
1463
(196 364 546 650) (224 416 600 700) (224 442 644 750)
1464
(252 476 690 816) (270 504 750 900) (300 560 810 960)
1465
(312 588 870 1050) (336 644 952 1110) (360 700 1020 1200)
1466
(390 728 1050 1260) (420 784 1140 1350) (450 812 1200 1440)
1467
(480 868 1290 1530) (510 924 1350 1620) (540 980 1440 1710)
1468
(570 1036 1530 1800) (570 1064 1590 1890) (600 1120 1680 1980)
1469
(630 1204 1770 2100) (660 1260 1860 2220) (720 1316 1950 2310)
1470
(750 1372 2040 2430))) ;; version 1 ~ 40
1471
(defun ecc-words-capacity (version level)
1472
(aref *ecc-codewords-table* version (level->index level)))
1473
(defun data-words-capacity (version level)
1474
(- (codeword-capacity version) (ecc-words-capacity version level)))
1476
;;; (Part II of) Table 9 - Error Correction blocks
1477
;;; varies between version and level
1478
(defvar *ecc-blocks*
1479
;; (version, level) =>
1480
;; (# of ec codewords for each blk, # of blk 1, # of data words for blk 1,
1481
;; # of blk 2, # of data words for blk 2)
1482
;; :level-l :level-m :level-q :level-h
1483
#3A(((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0)) ; no such version
1484
((7 1 19 0 0) (10 1 16 0 0) (13 1 13 0 0) (17 1 9 0 0)) ; Version 1
1485
((10 1 34 0 0) (16 1 28 0 0) (22 1 22 0 0) (28 1 16 0 0))
1486
((15 1 55 0 0) (26 1 44 0 0) (18 2 17 0 0) (22 2 13 0 0))
1487
((20 1 80 0 0) (18 2 32 0 0) (26 2 24 0 0) (16 4 9 0 0))
1488
((26 1 108 0 0) (24 2 43 0 0) (18 2 15 2 16) (22 2 11 2 12)) ; Version 5
1489
((18 2 68 0 0) (16 4 27 0 0) (24 4 19 0 0) (28 4 15 0 0))
1490
((20 2 78 0 0) (18 4 31 0 0) (18 2 14 4 15) (26 4 13 1 14))
1491
((24 2 97 0 0) (22 2 38 2 39) (22 4 18 2 19) (26 4 14 2 15))
1492
((30 2 116 0 0) (22 3 36 2 37) (20 4 16 4 17) (24 4 12 4 13))
1493
((18 2 68 2 69) (26 4 43 1 44) (24 6 19 2 20) (28 6 15 2 16)) ; Version 10
1494
((20 4 81 0 0) (30 1 50 4 51) (28 4 22 4 23) (24 3 12 8 13))
1495
((24 2 92 2 93) (22 6 36 2 37) (26 4 20 6 21) (28 7 14 4 15))
1496
((26 4 107 0 0) (22 8 37 1 38) (24 8 20 4 21) (22 12 11 4 12))
1497
((30 3 115 1 116) (24 4 40 5 41) (20 11 16 5 17) (24 11 12 5 13))
1498
((22 5 87 1 88) (24 5 41 5 42) (30 5 24 7 25) (24 11 12 7 13)) ; Version 15
1499
((24 5 98 1 99) (28 7 45 3 46) (24 15 19 2 20) (30 3 15 13 16))
1500
((28 1 107 5 108) (28 10 46 1 47) (28 1 22 15 23) (28 2 14 17 15))
1501
((30 5 120 1 121) (26 9 43 4 44) (28 17 22 1 23) (28 2 14 19 15))
1502
((28 3 113 4 114) (26 3 44 11 45) (26 17 21 4 22) (26 9 13 16 14))
1503
((28 3 107 5 108) (26 3 41 13 42) (30 15 24 5 25) (28 15 15 10 16)) ; Version 20
1504
((28 4 116 4 117) (26 17 42 0 0) (28 17 22 6 23) (30 19 16 6 17))
1505
((28 2 111 7 112) (28 17 46 0 0) (30 7 24 16 25) (24 34 13 0 0))
1506
((30 4 121 5 122) (28 4 47 14 48) (30 11 24 14 25) (30 16 15 14 16))
1507
((30 6 117 4 118) (28 6 45 14 46) (30 11 24 16 25) (30 30 16 2 17))
1508
((26 8 106 4 107) (28 8 47 13 48) (30 7 24 22 25) (30 22 15 13 16)) ; Version 25
1509
((28 10 114 2 115) (28 19 46 4 47) (28 28 22 6 23) (30 33 16 4 17))
1510
((30 8 122 4 123) (28 22 45 3 46) (30 8 23 26 24) (30 12 15 28 16))
1511
((30 3 117 10 118) (28 3 45 23 46) (30 4 24 31 25) (30 11 15 31 16))
1512
((30 7 116 7 117) (28 21 45 7 46) (30 1 23 37 24) (30 19 15 26 16))
1513
((30 5 115 10 116) (28 19 47 10 48) (30 15 24 25 25) (30 23 15 25 16)) ; Version 30
1514
((30 13 115 3 116) (28 2 46 29 47) (30 42 24 1 25) (30 23 15 28 16))
1515
((30 17 115 0 0) (28 10 46 23 47) (30 10 24 35 25) (30 19 15 35 16))
1516
((30 17 115 1 116) (28 14 46 21 47) (30 29 24 19 25) (30 11 15 46 16))
1517
((30 13 115 6 116) (28 14 46 23 47) (30 44 24 7 25) (30 59 16 1 17))
1518
((30 12 121 7 122) (28 12 47 26 48) (30 39 24 14 25) (30 22 15 41 16)) ; Version 35
1519
((30 6 121 14 122) (28 6 47 34 48) (30 46 24 10 25) (30 2 15 64 16))
1520
((30 17 122 4 123) (28 29 46 14 47) (30 49 24 10 25) (30 24 15 46 16))
1521
((30 4 122 18 123) (28 13 46 32 47) (30 48 24 14 25) (30 42 15 32 16))
1522
((30 20 117 4 118) (28 40 47 7 48) (30 43 24 22 25) (30 10 15 67 16))
1523
((30 19 118 6 119) (28 18 47 31 48) (30 34 24 34 25) (30 20 15 61 16)) ; Version 40
1525
(defun ecc-block-nums (version level)
1526
"# of ec codewords for each blk, # of blk 1, # of data words for blk 1, ..."
1527
(let ((lidx (level->index level)))
1528
(values (aref *ecc-blocks* version lidx 0)
1529
(aref *ecc-blocks* version lidx 1)
1530
(aref *ecc-blocks* version lidx 2)
1531
(aref *ecc-blocks* version lidx 3)
1532
(aref *ecc-blocks* version lidx 4))))
1534
(defun minimum-version (init-version nbytes level)
1535
"minimum version that can hold NBYTES data words, or INIT-VERSION if bigger"
1536
(do ((v init-version (1+ v)))
1538
(when (>= (data-words-capacity v level) nbytes)
1539
(return-from minimum-version v))))
1541
(defun version-range (version)
1543
((<= 1 version 9) 0)
1544
((<= 10 version 26) 1)
1545
((<= 27 version 40) 2)))
1547
;;; Table 3 - Number of bits in character count indicator for QR Code 2005
1548
(defvar *char-count-indicator*
1549
;; :numeric :alnum :byte :kanji
1550
#2A((10 9 8 8) ; version-range 0
1551
(12 11 16 10) ; version-range 1
1552
(14 13 16 12))) ; version-range 2
1553
(defun char-count-bits (version mode)
1554
(let ((i (version-range version))
1555
(j (mode->index mode)))
1556
(aref *char-count-indicator* i j)))
1558
;;; Table E.1 - Row/column coordinates of center modules of alignment patterns
1559
;;; varies between versions
1560
(defvar *align-coord-table*
1561
#2A((0 ()) ; 0, no such version
1562
(0 ()) (1 (6 18)) (1 (6 22))
1563
(1 (6 26)) (1 (6 30)) (1 (6 34))
1564
(6 (6 22 38)) (6 (6 24 42)) (6 (6 26 46))
1565
(6 (6 28 50)) (6 (6 30 54)) (6 (6 32 58))
1566
(6 (6 34 62)) (13 (6 26 46 66)) (13 (6 26 48 70))
1567
(13 (6 26 50 74)) (13 (6 30 54 78)) (13 (6 30 56 82))
1568
(13 (6 30 58 86)) (13 (6 34 62 90)) (22 (6 28 50 72 94))
1569
(22 (6 26 50 74 98)) (22 (6 30 54 78 102)) (22 (6 28 54 80 106))
1570
(22 (6 32 58 84 110)) (22 (6 30 58 86 114)) (22 (6 34 62 90 118))
1571
(33 (6 26 50 74 98 122)) (33 (6 30 54 78 102 126)) (33 (6 26 52 78 104 130))
1572
(33 (6 30 56 82 108 134)) (33 (6 34 60 86 112 138)) (33 (6 30 58 86 114 142))
1573
(33 (6 34 62 90 118 146)) (46 (6 30 54 78 102 126 150)) (46 (6 24 50 76 102 128 154))
1574
(46 (6 28 54 80 106 132 158)) (46 (6 32 58 84 110 136 162)) (46 (6 26 54 82 110 138 166))
1575
(46 (6 30 58 86 114 142 170)))
1576
"# of Alignment Patterns, row/column coordinates of center modules.")
1577
(defun valid-center-p (x y modules)
1578
"The alignment center module is not in Finder Patterns."
1579
(not (or (and (<= 0 x 8) (<= 0 y 8)) ; upleft finder pattern
1581
(<= (- modules 8) y (- modules 1))) ; upright finder pattern
1582
(and (<= (- modules 8) x (- modules 1))
1584
(defun align-centers (version)
1585
"list of all valid alignment pattern center modules under VERSION"
1586
(let* ((modules (matrix-modules version))
1587
(coords (aref *align-coord-table* version 1))
1588
(len (length coords))
1591
(loop for j from i to (- len 1) do
1592
(let ((x (nth i coords))
1594
(when (valid-center-p x y modules)
1595
(push (list x y) centers))
1597
(when (valid-center-p y x modules)
1598
(push (list y x) centers))))))
1601
(defun mask-condition (indicator)
1604
;; (i + j) mod 2 == 0
1605
(0 (= (mod (+ i j) 2) 0))
1610
;; (i + j) mod 3 == 0
1611
(3 (= (mod (+ i j) 3) 0))
1612
;; ((i/2) + (j/3)) mod 2 == 0
1613
(4 (= (mod (+ (floor i 2) (floor j 3)) 2) 0))
1614
;; (i*j) mod 2 + (i*j) mod 3 == 0
1615
(5 (= (+ (mod (* i j) 2) (mod (* i j) 3)) 0))
1616
;; ((i*j) mod 2 + (i*j) mod 3)) mod 2 == 0
1617
(6 (= (mod (+ (mod (* i j) 2) (mod (* i j) 3)) 2) 0))
1618
;; ((i+j) mod 2 + (i*j) mod 3)) mod 2 == 0
1619
(7 (= (mod (+ (mod (+ i j) 2) (mod (* i j) 3)) 2) 0)))))
1621
(defvar *ecc-level-indicator* #((0 1) (0 0) (1 1) (1 0))
1622
":level-l :level-m :level-q :level-h")
1623
(defun level-indicator (level)
1624
(aref *ecc-level-indicator* (level->index level)))
1625
(defvar *mask-pattern-reference*
1626
#((0 0 0) (0 0 1) (0 1 0) (0 1 1)
1627
(1 0 0) (1 0 1) (1 1 0) (1 1 1)))
1628
(defun mask-pattern-ref (ind)
1629
(aref *mask-pattern-reference* ind))
1631
;;; png backend for QR code symbol
1633
(defun set-color (pngarray x y color)
1634
(setf (aref pngarray x y 0) color)
1635
(setf (aref pngarray x y 1) color)
1636
(setf (aref pngarray x y 2) color))
1638
(defun qr-symbol-to-png (symbol pixsize margin)
1639
"return the qr symbol written into a PNG object with PIXSIZE
1640
pixels for each module, and MARGIN pixels on all four sides"
1641
(with-slots (matrix modules) symbol
1642
(let* ((size (+ (* modules pixsize) (* margin 2)))
1643
(qrpng (make-instance 'png :width size :height size))
1644
(qrarray (dat/png::data-array qrpng)))
1647
(if (and (<= margin x (- size margin 1))
1648
(<= margin y (- size margin 1)))
1649
(let ((i (floor (- x margin) pixsize))
1650
(j (floor (- y margin) pixsize)))
1651
(if (dark-module-p matrix i j)
1652
(set-color qrarray x y 0)
1653
(set-color qrarray x y 255)))
1655
(set-color qrarray x y 255))))
1658
(defun qr-encode-png (text &key (path "qrcode.png") (version 1) (level :level-m)
1659
(mode nil) (pixsize 9) (margin 8))
1660
(let ((symbol (encode-symbol text :version version :level level :mode mode)))
1661
(write-png (qr-symbol-to-png symbol pixsize margin) path)))
1663
(defmethod serialize ((self string) (format (eql :qrcode)) &key path (version 1) (level :level-m))
1664
(declare (ignore format))
1665
(qr-encode-png self :path path :version version :level level))
1667
(defun qr-encode-png-stream (text stream &key (version 1) (level :level-m)
1668
(mode nil) (pixsize 9) (margin 8))
1669
(let ((symbol (encode-symbol text :version version :level level :mode mode)))
1670
(write-png-stream (qr-symbol-to-png symbol pixsize margin) stream)))
1672
(defun qr-encode-png-bytes (bytes &key (fpath "kanji.png") (version 1)
1673
(level :level-m) (mode nil) (pixsize 9) (margin 8))
1674
(let ((symbol (encode-symbol-bytes bytes :version version :level level
1676
(write-png (qr-symbol-to-png symbol pixsize margin) fpath)))
1678
(defun qr-encode-png-bytes-stream (bytes stream &key (version 1) (level :level-m)
1679
(mode nil) (pixsize 9) (margin 8))
1680
(let ((symbol (encode-symbol-bytes bytes :version version :level level
1682
(write-png-stream (qr-symbol-to-png symbol pixsize margin) stream)))