#lang racket/base (require racket/contract racket/list racket/vector "../base.rkt" "../data.rkt" "bits.rkt" "bmp.rkt" "constants.rkt" "galois.rkt" "layout.rkt" "version.rkt") (provide/contract [qr-encode-data (-> qr-spec? bytes?)] [qr-encode/bmp (-> qr-spec? bmp?)]) (define (encode-data/pad data version edc-level) (let* ([max-words (qr-data-word-count version edc-level)] [max-bits (* max-words 8)] [bits (qr-data->bits data version)] [bit-count (length bits)]) (cond [(> bit-count max-bits) (error "too many data bits" bit-count)] [(>= bit-count (- max-bits 8)) (bits->bytes bits)] [else (let* ([words (bits->bytes (append bits '(#f #f #f #f)))] [word-count (bytes-length words)] [pad-count (- max-words word-count)]) (bytes-append words (list->bytes (build-list pad-count (lambda (i) (if (even? i) #b11101100 #b00010001))))))]))) (define (encode-data/ecd-blocks data version edc-level) (let-values ([(data-words) (encode-data/pad data version edc-level)] [(data-counts ecd-counts) (qr-data/edc-block-sizes version edc-level)]) (let* ([data-blocks (let loop ([counts data-counts] [start 0]) (if (null? counts) '() (let* ([end (+ start (car counts))] [block (subbytes data-words start end)]) (cons block (loop (cdr counts) end)))))] [ecd-blocks (map make-ecd-block data-blocks ecd-counts)]) (values data-blocks ecd-blocks)))) (define (interleave . lsts) (let loop ([lsts lsts]) (let ([lsts (filter (lambda (l) (not (null? l))) lsts)]) (if (null? lsts) '() (append (map car lsts) (loop (map cdr lsts))))))) (define (make-ecd-block data len) (let ([gs (make-rs-generator len)]) (do ([ds (bytes->list data) (cdr ds)] [bs (make-vector len 0) (let ([x (gf+ (vector-ref bs (sub1 len)) (car ds))]) (vector-map gf+ (vector-append #(0) (vector-drop-right bs 1)) (vector-map (lambda (g) (gf* g x)) gs)))]) ((null? ds) (list->bytes (reverse (vector->list bs))))))) (define (qr-encode-data spec) (let-values ([(data-blocks edc-blocks) (encode-data/ecd-blocks (qr-spec-data spec) (qr-spec-version spec) (qr-spec-edc-level spec))]) (bytes-append (list->bytes (apply interleave (map bytes->list data-blocks))) (list->bytes (apply interleave (map bytes->list edc-blocks)))))) (define (apply-data-masks sym mask) (for/list ([n (in-range 8)]) (qr-apply-data-mask n sym mask))) (define (score-masked sym) (define (count-runs lst [is-equal? eqv?]) (if (null? lst) '() (let next ([x (car lst)] [n 1] [lst (cdr lst)]) (cond [(null? lst) (list n)] [(is-equal? x (car lst)) (next x (add1 n) (cdr lst))] [else (cons n (next (car lst) 1 (cdr lst)))])))) (define (all-eq? x . xs) (andmap (lambda (y) (eq? x y)) xs)) (define (count-locator-patterns bits) (let ([bits (append '(#f #f #f #f) bits '(#f #f #f #f))]) (for/sum ([i (in-range (- (length bits) 11))]) (let ([bits (take (drop bits i) 11)]) (if (or (equal? bits '(#f #f #f #f #t #f #t #t #t #f #t)) (equal? bits '(#t #f #t #t #t #f #t #f #f #f #f))) 1 0))))) (let ([size (bmp-width sym)]) (let ([runs (for/sum ([i (in-range size)]) (apply + (map (lambda (len) (if (>= len 5) (+ 3 (- len 5)) 0)) (append (count-runs (for/list ([j (in-range size)]) (get-px sym i j))) (count-runs (for/list ([j (in-range size)]) (get-px sym j i)))))))] [blocks (for*/sum ([y (in-range (sub1 size))] [x (in-range (sub1 size))]) (if (all-eq? (get-px sym x y) (get-px sym (add1 x) y) (get-px sym x (add1 y)) (get-px sym (add1 x) (add1 y))) 3 0))] [locators (for/sum ([i (in-range size)]) (* (+ (count-locator-patterns (for/list ([j (in-range size)]) (get-px sym i j))) (count-locator-patterns (for/list ([j (in-range size)]) (get-px sym j i)))) 40))] [proportion (let ([total-pixels (* size size)] [set-pixels (for*/sum ([y (in-range size)] [x (in-range size)] #:when (get-px sym x y)) 1)]) (* 10 (quotient (abs (- 50 (quotient (* 100 set-pixels) total-pixels))) 5)))]) (+ runs blocks locators proportion)))) (define (write-format-info! version edc-level mask bmp) (let* ([bits (append (integer->bits (vector-memv edc-level #(M L H Q)) 2) (integer->bits mask 3))] [bch (gf-mod (arithmetic-shift (bits->integer bits) 10) #b10100110111)] [bits (append bits (integer->bits bch 10))] [bits (map (lambda (b1 b2) (not (eq? b1 b2))) bits (integer->bits #b101010000010010 15))]) (let ([side (qr-size version)]) (for ([i (in-naturals)] [b (in-list (reverse bits))] #:when b) (cond [(<= i 5) (set-px! bmp 8 i) (set-px! bmp (- side 1 i) 8)] [(<= i 7) (set-px! bmp 8 (+ i 1)) (set-px! bmp (- side 1 i) 8)] [(<= i 8) (set-px! bmp 7 8) (set-px! bmp 8 (- side 6))] [else (set-px! bmp (- 14 i) 8) (set-px! bmp 8 (+ (- side 15) i))])) bmp))) (define (write-version-info! version bmp) (let* ([bch (vector-ref qr-version-edc-bits-table (- version 7))] [bits (append (integer->bits version 6) (integer->bits bch 12))]) (let ([size (bmp-width bmp)]) (for ([b (in-list (reverse bits))] [i (in-naturals)] #:when b) (let-values ([(q r) (quotient/remainder i 3)]) (set-px! bmp (+ (- size 11) r) q) (set-px! bmp q (+ (- size 11) r))))))) (define (qr-encode/bmp spec) (let* ([version (qr-spec-version spec)] [bits (qr-encode-data spec)] [sym (qr-template version)] [mask (qr-data-mask version)]) (qr-layout-data! sym mask bits) (let ([masked (apply-data-masks sym mask)]) (for ([sym (in-list masked)] [n (in-naturals)]) (when (qr-has-format-information? version) (write-format-info! version (qr-spec-edc-level spec) n sym)) (when (qr-has-version-information? version) (write-version-info! version sym))) (car (sort masked < #:key score-masked #:cache-keys? #t)))))