├── test ├── data │ ├── generated │ │ ├── .gitignore │ │ ├── eci.c │ │ ├── generator.c │ │ ├── qrcodegen.h │ │ └── qrcodegen.c │ ├── 1x1.png │ ├── eci.png │ ├── 1x1.jpeg │ ├── black.png │ ├── eci.jpeg │ ├── flipped.jpeg │ ├── flipped.png │ ├── Hello+World.png │ ├── Hello+World.jpeg │ ├── big_image_with_two_qrcodes.png │ └── big_image_with_two_qrcodes.jpeg └── index.js ├── .github ├── dependabot.yml └── workflows │ ├── test.yml │ └── npm-publish.yml ├── deps └── quirc │ ├── binding.gyp │ ├── quirc_internal.h │ ├── quirc.c │ ├── quirc.h │ ├── version_db.c │ ├── decode.c │ └── identify.c ├── .gitignore ├── binding.gyp ├── src ├── node_quirc_decode.h ├── node-quirc.cc └── node_quirc_decode.c ├── package.json ├── LICENSE ├── README.md └── index.js /test/data/generated/.gitignore: -------------------------------------------------------------------------------- 1 | *.png 2 | -------------------------------------------------------------------------------- /test/data/1x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/1x1.png -------------------------------------------------------------------------------- /test/data/eci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/eci.png -------------------------------------------------------------------------------- /test/data/1x1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/1x1.jpeg -------------------------------------------------------------------------------- /test/data/black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/black.png -------------------------------------------------------------------------------- /test/data/eci.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/eci.jpeg -------------------------------------------------------------------------------- /test/data/flipped.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/flipped.jpeg -------------------------------------------------------------------------------- /test/data/flipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/flipped.png -------------------------------------------------------------------------------- /test/data/Hello+World.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/Hello+World.png -------------------------------------------------------------------------------- /test/data/Hello+World.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/Hello+World.jpeg -------------------------------------------------------------------------------- /test/data/big_image_with_two_qrcodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/big_image_with_two_qrcodes.png -------------------------------------------------------------------------------- /test/data/big_image_with_two_qrcodes.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaworu/node-quirc/HEAD/test/data/big_image_with_two_qrcodes.jpeg -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: / 5 | schedule: 6 | interval: daily 7 | commit-message: 8 | prefix: "npm:" 9 | open-pull-requests-limit: 5 10 | rebase-strategy: disabled 11 | - package-ecosystem: github-actions 12 | directory: / 13 | schedule: 14 | interval: daily 15 | commit-message: 16 | prefix: "ci:" 17 | open-pull-requests-limit: 5 18 | rebase-strategy: disabled 19 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | strategy: 8 | matrix: 9 | node-version: [14.x, 16.x, 18.x, 19.x, 20.x] 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Setup Node.js ${{ matrix.node-version }} 13 | uses: actions/setup-node@v4 14 | with: 15 | node-version: ${{ matrix.node-version }} 16 | - name: Checkout code 17 | uses: actions/checkout@v4 18 | - name: Install dependencies 19 | run: npm install 20 | - name: Test 21 | run: npm test 22 | env: 23 | CI: true 24 | -------------------------------------------------------------------------------- /deps/quirc/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "target_defaults": { 3 | "defines": [ 4 | "QUIRC_MAX_REGIONS=65534" 5 | ] 6 | }, 7 | 8 | "targets": [ 9 | { 10 | "target_name": "quirc", 11 | "product_prefix": "lib", 12 | "type": "static_library", 13 | "sources": [ 14 | "decode.c", 15 | "identify.c", 16 | "quirc.c", 17 | "version_db.c" 18 | ], 19 | "direct_dependent_settings": { 20 | "include_dirs": [ 21 | "." 22 | ], 23 | } 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/ 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: publish to NPM 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | npm-publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | - name: Publish on version update 15 | uses: pascalgn/npm-publish-action@1.3.9 16 | with: 17 | tag_name: "v%s" 18 | tag_message: "v%s" 19 | create_tag: "true" 20 | commit_pattern: "^Release (\\S+)" 21 | workspace: "." 22 | publish_command: "yarn" 23 | publish_args: "--non-interactive" 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 27 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "node-quirc", 5 | "sources": [ 6 | "src/node-quirc.cc" 7 | ], 8 | "include_dirs": [ 9 | " /* for size_t */ 8 | #include /* for uint8_t */ 9 | 10 | struct nq_code_list; 11 | struct nq_code; 12 | 13 | struct nq_code_list *nq_decode(const uint8_t *img, size_t img_len, size_t width, size_t height); 14 | const char *nq_code_list_err(const struct nq_code_list *list); 15 | unsigned int nq_code_list_size(const struct nq_code_list *list); 16 | const struct nq_code *nq_code_at(const struct nq_code_list *list, unsigned int index); 17 | void nq_code_list_free(struct nq_code_list *list); 18 | 19 | const char *nq_code_err(const struct nq_code *code); 20 | int nq_code_version(const struct nq_code *code); 21 | const char *nq_code_ecc_level_str(const struct nq_code *code); 22 | int nq_code_mask(const struct nq_code *code); 23 | const char *nq_code_mode_str(const struct nq_code *code); 24 | const char *nq_code_eci_str(const struct nq_code *code); 25 | const uint8_t *nq_code_payload(const struct nq_code *code); 26 | size_t nq_code_payload_len(const struct nq_code *code); 27 | 28 | #endif /* ndef NODE_QUIRC_DECODE_H */ 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-quirc", 3 | "version": "2.3.0", 4 | "description": "quirc for nodejs (QR decoder)", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node-gyp configure build && ./node_modules/.bin/mocha --reporter spec --ui bdd", 8 | "prepare": "rm -r build || (exit 0)" 9 | }, 10 | "engines": { 11 | "node": ">= 10" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/kAworu/node-quirc" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/kAworu/node-quirc/issues" 19 | }, 20 | "keywords": [ 21 | "QR", 22 | "QR code", 23 | "qrcode", 24 | "barcode", 25 | "2D code", 26 | "decoder", 27 | "scan", 28 | "scanner" 29 | ], 30 | "author": "Alexandre Perrin ", 31 | "license": "MIT", 32 | "gypfile": true, 33 | "dependencies": { 34 | "bindings": "^1.5.0", 35 | "nan": "^2.17.0" 36 | }, 37 | "devDependencies": { 38 | "chai": "^4.2.0", 39 | "jpeg-js": "^0.4.2", 40 | "mocha": "^11.0.1" 41 | }, 42 | "contributors": [ 43 | "Alexandre Perrin (https://github.com/kAworu)", 44 | "Daniel Beer (https://github.com/dlbeer)" 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | node-quirc is licensed under the MIT License. node-quirc include code from the 2 | quirc library (license is reproduced below). 3 | 4 | The MIT License (MIT) 5 | 6 | Copyright (c) 2016-2019 Alexandre Perrin 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | 26 | ------------------------------------------------------------------------------ 27 | quirc -- QR-code recognition library 28 | Copyright (C) 2010-2012 Daniel Beer 29 | 30 | Permission to use, copy, modify, and/or distribute this software for 31 | any purpose with or without fee is hereby granted, provided that the 32 | above copyright notice and this permission notice appear in all 33 | copies. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 36 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 37 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 38 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 39 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 40 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 41 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 42 | PERFORMANCE OF THIS SOFTWARE. 43 | -------------------------------------------------------------------------------- /test/data/generated/eci.c: -------------------------------------------------------------------------------- 1 | /* 2 | * eci.c - Generate one QR code on stdout containing a ECI segment (UTF-8). 3 | * 4 | * Compile with: 5 | * cc -std=c11 qrcodegen.c eci.c $(pkg-config --cflags --libs libpng) -o eci 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "qrcodegen.h" 13 | #include 14 | 15 | 16 | int 17 | main(int argc, char **argv) 18 | { 19 | const int dot_size = 3, margin = 4; 20 | const char white = 0xFF, black = 0x00; 21 | /* taken from https://www.w3.org/2001/06/utf-8-test/UTF-8-demo.html */ 22 | const char *data = u8"ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ"; 23 | const size_t datalen = strlen(data); 24 | uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX], tmp[qrcodegen_BUFFER_LEN_MAX]; 25 | png_structp png_ptr; 26 | png_infop info_ptr; 27 | 28 | uint8_t *eci = calloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ECI, 0), sizeof(uint8_t)); 29 | uint8_t *buf = calloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, datalen), sizeof(uint8_t)); 30 | uint8_t *bytes = calloc(datalen, sizeof(uint8_t)); 31 | if (eci == NULL || buf == NULL || bytes == NULL) 32 | err(1, "calloc"); 33 | 34 | for (size_t i = 0; i < datalen; i++) 35 | bytes[i] = (uint8_t)data[i]; 36 | 37 | struct qrcodegen_Segment segs[] = { 38 | qrcodegen_makeEci(/* ECI_UTF_8 */26, eci), 39 | qrcodegen_makeBytes(bytes, datalen, buf), 40 | }; 41 | bool ret = qrcodegen_encodeSegments(segs, 2, qrcodegen_Ecc_LOW, tmp, qrcode); 42 | if (!ret) 43 | err(1, "qrcodegen_encodeSegments"); 44 | const int width = qrcodegen_getSize(qrcode); 45 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 46 | if (png_ptr == NULL) 47 | err(1, "png_create_write_struct"); 48 | info_ptr = png_create_info_struct(png_ptr); 49 | if (info_ptr == NULL) 50 | err(1, "png_create_info_struct"); 51 | if (setjmp(png_jmpbuf(png_ptr))) 52 | err(1, "setjmp"); 53 | png_init_io(png_ptr, stdout); 54 | png_set_IHDR(png_ptr, info_ptr, 55 | (width + margin * 2) * dot_size, 56 | (width + margin * 2) * dot_size, 57 | 1 /* depth */, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, 58 | PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 59 | png_write_info(png_ptr, info_ptr); 60 | png_set_packing(png_ptr); 61 | unsigned char *row = calloc((width + margin * 2), dot_size); 62 | if (row == NULL) 63 | err(1, "calloc"); 64 | for (int y = -margin; y < width + margin; y++) { 65 | for (int x = -margin; x < width + margin; x++) { 66 | unsigned char dot; 67 | if (y < 0 || y > width - 1 || x < 0 || x > width - 1) 68 | dot = white; 69 | else 70 | dot = qrcodegen_getModule(qrcode, x, y) ? black : white; 71 | for (int d = 0; d < dot_size; d++) 72 | row[(x + margin) * dot_size + d] = dot; 73 | } 74 | for (int d = 0; d < dot_size; d++) 75 | png_write_row(png_ptr, row); 76 | } 77 | 78 | png_write_end(png_ptr, info_ptr); 79 | free(row); 80 | 81 | /* cleanup */ 82 | free(bytes); 83 | free(buf); 84 | free(eci); 85 | png_destroy_write_struct(&png_ptr, &info_ptr); 86 | 87 | return (EXIT_SUCCESS); 88 | } 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![NPM Version](https://img.shields.io/npm/v/node-quirc.svg)](https://npmjs.org/package/node-quirc) 2 | ![Test](https://github.com/kAworu/node-quirc/workflows/Test/badge.svg) 3 | 4 | # node-quirc 5 | A Node.js Addon of the quirc library (QR decoder library - https://github.com/dlbeer/quirc). 6 | 7 | # installation 8 | First, You need libpng and libjpeg (and their header files) installed. Then, simply 9 | ``` 10 | % npm install node-quirc 11 | ``` 12 | 13 | # documentation 14 | node-quirc aim to be simple to use, the module exposes a `decode()` function 15 | and a `constants` object. 16 | 17 | 18 | ## decode(img[, callback]) 19 | `img` must be either a `Buffer` of a PNG or JPEG encoded image file, or a 20 | decoded image in [`ImageData`](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) 21 | format with 1 (grayscale), 3 (RGB) or 4 (RGBA) channels. 22 | 23 | When `callback` is provided, it is expected to be a "classic" Node.js callback 24 | function, taking an error as first argument and the result as second argument. 25 | Because the provided image file may contains several QR Code, the result is 26 | always an array on success. 27 | 28 | When `decode` is called only with `img` as argument, a `Promise` is returned. 29 | 30 | ```javascript 31 | const fs = require("fs"); 32 | const quirc = require("node-quirc"); 33 | 34 | // load the image file 35 | const img = fs.readFileSync("./test/data/Hello+World.png"); 36 | 37 | // callback version 38 | quirc.decode(img, (err, codes) => { 39 | if (err) { 40 | // handle err. 41 | console.error(`decode failed: ${err.message}`); 42 | } else { 43 | // do something with codes. 44 | console.dir(codes); 45 | console.log(codes.map((code) => code.data.toString('utf8'))); 46 | } 47 | }); 48 | 49 | // Promise version 50 | quirc.decode(img).then((codes) => { 51 | // do something with codes. 52 | }).catch((err) => { 53 | // handle err. 54 | }); 55 | 56 | // alternatively, use an already-loaded ImageData, e.g. from the `canvas` library 57 | const context = canvas.getContext('2d'); 58 | const imageData = context.getImageData(0, 0, 800, 600); 59 | quirc.decode(imageData).then((codes) => { 60 | // do something with codes. 61 | console.log(`codes read from ImageData (size=${ 62 | imageData.data.length 63 | }, width=${imageData.width}, height=${ 64 | imageData.height 65 | }):`, codes); 66 | }).catch((err) => { 67 | // handle err. 68 | }); 69 | ``` 70 | 71 | output: 72 | 73 | ``` 74 | [ 75 | { 76 | version: 1, 77 | ecc_level: 'H', 78 | mask: 1, 79 | mode: 'BYTE', 80 | eci: 'UTF_8', 81 | data: Buffer [Uint8Array] [ 72, 101, 108, 108, 111 ] 82 | }, 83 | { 84 | version: 1, 85 | ecc_level: 'H', 86 | mask: 3, 87 | mode: 'BYTE', 88 | eci: 'UTF_8', 89 | data: Buffer [Uint8Array] [ 87, 111, 114, 108, 100 ] 90 | } 91 | ] 92 | [ 'Hello', 'World' ] 93 | ``` 94 | 95 | ## constants 96 | see https://github.com/kAworu/node-quirc/blob/master/index.js#L68-L99 97 | 98 | 99 | # testing 100 | Clone the repo and then simply 101 | ``` 102 | % npm install && npm test 103 | ``` 104 | 105 | # license 106 | MIT, see [LICENSE](./LICENSE). 107 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Our C++ Addon 4 | const addon = require('bindings')('node-quirc.node'); 5 | 6 | function decodeEncoded(img, callback) { 7 | return addon.decodeEncoded(img, callback); 8 | } 9 | 10 | function isImageDimension(number) { 11 | return ( 12 | typeof number === 'number' && 13 | number > 0 && 14 | (number | 0) === number && 15 | !isNaN(number) 16 | ); 17 | } 18 | 19 | function decodeRaw(img, callback) { 20 | if (!isImageDimension(img.width)) { 21 | throw new Error( 22 | `unexpected width value for image: ${img.width}` 23 | ) 24 | } 25 | if (!isImageDimension(img.height)) { 26 | throw new Error( 27 | `unexpected height value for image: ${img.height}` 28 | ) 29 | } 30 | const channels = img.data.length / img.width / img.height; 31 | if (channels !== 1 && channels !== 3 && channels !== 4) { 32 | throw new Error( 33 | `unsupported ${channels}-channel image, expected 1, 3, or 4` 34 | ); 35 | } 36 | return addon.decodeRaw(img.data, img.width, img.height, callback); 37 | } 38 | 39 | function maybePromisify(fn) { 40 | return (...args) => { 41 | if (args.length < fn.length) { 42 | return new Promise((resolve, reject) => { 43 | fn(...args, (err, results) => { 44 | if (err) { 45 | return reject(err); 46 | } else { 47 | return resolve(results); 48 | } 49 | }); 50 | }); 51 | } else { 52 | return fn(...args); 53 | } 54 | }; 55 | } 56 | 57 | // public API 58 | module.exports = { 59 | decode: maybePromisify((img, callback) => { 60 | if (Buffer.isBuffer(img)) { 61 | return decodeEncoded(img, callback); 62 | } else if (img && typeof img === "object") { 63 | return decodeRaw(img, callback); 64 | } else { 65 | throw new TypeError("img must be a Buffer or ImageData"); 66 | } 67 | }), 68 | constants: { 69 | // QR-code versions. 70 | VERSION_MIN: 1, 71 | VERSION_MAX: 40, 72 | // QR-code ECC levels. 73 | ECC_LEVEL_M: "M", 74 | ECC_LEVEL_L: "L", 75 | ECC_LEVEL_H: "H", 76 | ECC_LEVEL_Q: "Q", 77 | // QR-code encoding modes. 78 | MODE_NUMERIC: "NUMERIC", 79 | MODE_ALNUM: "ALNUM", 80 | MODE_BYTE: "BYTE", 81 | MODE_KANJI: "KANJI", 82 | // Common character encodings 83 | ECI_ISO_8859_1: "ISO_8859_1", 84 | ECI_IBM437: "IBM437", 85 | ECI_ISO_8859_2: "ISO_8859_2", 86 | ECI_ISO_8859_3: "ISO_8859_3", 87 | ECI_ISO_8859_4: "ISO_8859_4", 88 | ECI_ISO_8859_5: "ISO_8859_5", 89 | ECI_ISO_8859_6: "ISO_8859_6", 90 | ECI_ISO_8859_7: "ISO_8859_7", 91 | ECI_ISO_8859_8: "ISO_8859_8", 92 | ECI_ISO_8859_9: "ISO_8859_9", 93 | ECI_WINDOWS_874: "WINDOWS_874", 94 | ECI_ISO_8859_13: "ISO_8859_13", 95 | ECI_ISO_8859_15: "ISO_8859_15", 96 | ECI_SHIFT_JIS: "SHIFT_JIS", 97 | ECI_UTF_8: "UTF_8", 98 | }, 99 | }; 100 | -------------------------------------------------------------------------------- /deps/quirc/quirc_internal.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef QUIRC_INTERNAL_H_ 18 | #define QUIRC_INTERNAL_H_ 19 | 20 | #include "quirc.h" 21 | 22 | #define QUIRC_PIXEL_WHITE 0 23 | #define QUIRC_PIXEL_BLACK 1 24 | #define QUIRC_PIXEL_REGION 2 25 | 26 | #ifndef QUIRC_MAX_REGIONS 27 | #define QUIRC_MAX_REGIONS 254 28 | #endif 29 | #define QUIRC_MAX_CAPSTONES 32 30 | #define QUIRC_MAX_GRIDS 8 31 | #define QUIRC_PERSPECTIVE_PARAMS 8 32 | 33 | #if QUIRC_MAX_REGIONS < UINT8_MAX 34 | #define QUIRC_PIXEL_ALIAS_IMAGE 1 35 | typedef uint8_t quirc_pixel_t; 36 | #elif QUIRC_MAX_REGIONS < UINT16_MAX 37 | #define QUIRC_PIXEL_ALIAS_IMAGE 0 38 | typedef uint16_t quirc_pixel_t; 39 | #else 40 | #error "QUIRC_MAX_REGIONS > 65534 is not supported" 41 | #endif 42 | 43 | struct quirc_region { 44 | struct quirc_point seed; 45 | int count; 46 | int capstone; 47 | }; 48 | 49 | struct quirc_capstone { 50 | int ring; 51 | int stone; 52 | 53 | struct quirc_point corners[4]; 54 | struct quirc_point center; 55 | double c[QUIRC_PERSPECTIVE_PARAMS]; 56 | 57 | int qr_grid; 58 | }; 59 | 60 | struct quirc_grid { 61 | /* Capstone indices */ 62 | int caps[3]; 63 | 64 | /* Alignment pattern region and corner */ 65 | int align_region; 66 | struct quirc_point align; 67 | 68 | /* Timing pattern endpoints */ 69 | struct quirc_point tpep[3]; 70 | int hscan; 71 | int vscan; 72 | 73 | /* Grid size and perspective transform */ 74 | int grid_size; 75 | double c[QUIRC_PERSPECTIVE_PARAMS]; 76 | }; 77 | 78 | struct quirc { 79 | uint8_t *image; 80 | quirc_pixel_t *pixels; 81 | int w; 82 | int h; 83 | 84 | int num_regions; 85 | struct quirc_region regions[QUIRC_MAX_REGIONS]; 86 | 87 | int num_capstones; 88 | struct quirc_capstone capstones[QUIRC_MAX_CAPSTONES]; 89 | 90 | int num_grids; 91 | struct quirc_grid grids[QUIRC_MAX_GRIDS]; 92 | }; 93 | 94 | /************************************************************************ 95 | * QR-code version information database 96 | */ 97 | 98 | #define QUIRC_MAX_VERSION 40 99 | #define QUIRC_MAX_ALIGNMENT 7 100 | 101 | struct quirc_rs_params { 102 | int bs; /* Small block size */ 103 | int dw; /* Small data words */ 104 | int ns; /* Number of small blocks */ 105 | }; 106 | 107 | struct quirc_version_info { 108 | int data_bytes; 109 | int apat[QUIRC_MAX_ALIGNMENT]; 110 | struct quirc_rs_params ecc[4]; 111 | }; 112 | 113 | extern const struct quirc_version_info quirc_version_db[QUIRC_MAX_VERSION + 1]; 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /deps/quirc/quirc.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include "quirc_internal.h" 20 | 21 | const char *quirc_version(void) 22 | { 23 | return "1.0"; 24 | } 25 | 26 | struct quirc *quirc_new(void) 27 | { 28 | struct quirc *q = malloc(sizeof(*q)); 29 | 30 | if (!q) 31 | return NULL; 32 | 33 | memset(q, 0, sizeof(*q)); 34 | return q; 35 | } 36 | 37 | void quirc_destroy(struct quirc *q) 38 | { 39 | free(q->image); 40 | /* q->pixels may alias q->image when their type representation is of the 41 | same size, so we need to be careful here to avoid a double free */ 42 | if (!QUIRC_PIXEL_ALIAS_IMAGE) 43 | free(q->pixels); 44 | free(q); 45 | } 46 | 47 | int quirc_resize(struct quirc *q, int w, int h) 48 | { 49 | uint8_t *image = NULL; 50 | quirc_pixel_t *pixels = NULL; 51 | 52 | /* 53 | * XXX: w and h should be size_t (or at least unsigned) as negatives 54 | * values would not make much sense. The downside is that it would break 55 | * both the API and ABI. Thus, at the moment, let's just do a sanity 56 | * check. 57 | */ 58 | if (w < 0 || h < 0) 59 | goto fail; 60 | 61 | /* 62 | * alloc a new buffer for q->image. We avoid realloc(3) because we want 63 | * on failure to be leave `q` in a consistant, unmodified state. 64 | */ 65 | image = calloc(w, h); 66 | if (!image) 67 | goto fail; 68 | 69 | /* compute the "old" (i.e. currently allocated) and the "new" 70 | (i.e. requested) image dimensions */ 71 | size_t olddim = q->w * q->h; 72 | size_t newdim = w * h; 73 | size_t min = (olddim < newdim ? olddim : newdim); 74 | 75 | /* 76 | * copy the data into the new buffer, avoiding (a) to read beyond the 77 | * old buffer when the new size is greater and (b) to write beyond the 78 | * new buffer when the new size is smaller, hence the min computation. 79 | */ 80 | (void)memcpy(image, q->image, min); 81 | 82 | /* alloc a new buffer for q->pixels if needed */ 83 | if (!QUIRC_PIXEL_ALIAS_IMAGE) { 84 | pixels = calloc(newdim, sizeof(quirc_pixel_t)); 85 | if (!pixels) 86 | goto fail; 87 | } 88 | 89 | /* alloc succeeded, update `q` with the new size and buffers */ 90 | q->w = w; 91 | q->h = h; 92 | free(q->image); 93 | q->image = image; 94 | if (!QUIRC_PIXEL_ALIAS_IMAGE) { 95 | free(q->pixels); 96 | q->pixels = pixels; 97 | } 98 | 99 | return 0; 100 | /* NOTREACHED */ 101 | fail: 102 | free(image); 103 | free(pixels); 104 | 105 | return -1; 106 | } 107 | 108 | int quirc_count(const struct quirc *q) 109 | { 110 | return q->num_grids; 111 | } 112 | 113 | static const char *const error_table[] = { 114 | [QUIRC_SUCCESS] = "Success", 115 | [QUIRC_ERROR_INVALID_GRID_SIZE] = "Invalid grid size", 116 | [QUIRC_ERROR_INVALID_VERSION] = "Invalid version", 117 | [QUIRC_ERROR_FORMAT_ECC] = "Format data ECC failure", 118 | [QUIRC_ERROR_DATA_ECC] = "ECC failure", 119 | [QUIRC_ERROR_UNKNOWN_DATA_TYPE] = "Unknown data type", 120 | [QUIRC_ERROR_DATA_OVERFLOW] = "Data overflow", 121 | [QUIRC_ERROR_DATA_UNDERFLOW] = "Data underflow" 122 | }; 123 | 124 | const char *quirc_strerror(quirc_decode_error_t err) 125 | { 126 | if (err >= 0 && err < sizeof(error_table) / sizeof(error_table[0])) 127 | return error_table[err]; 128 | 129 | return "Unknown error"; 130 | } 131 | -------------------------------------------------------------------------------- /test/data/generated/generator.c: -------------------------------------------------------------------------------- 1 | /* 2 | * generator.c - Generate *a lot* of QR code files. 3 | * 4 | * Compile with: 5 | * cc -std=c11 generator.c $(pkg-config --cflags --libs libpng libqrencode) -o generator 6 | */ 7 | 8 | /* glibc feature_test_macros madness */ 9 | #define _GNU_SOURCE /* for asprintf(3) */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | 20 | static const char *mode_str[] = { 21 | [QR_MODE_NUM] = "NUMERIC", 22 | [QR_MODE_AN] = "ALNUM", 23 | [QR_MODE_8] = "BYTE", 24 | [QR_MODE_KANJI] = "KANJI", 25 | }; 26 | 27 | static const char *ecc_level_str[] = { 28 | [QR_ECLEVEL_L] = "L", 29 | [QR_ECLEVEL_M] = "M", 30 | [QR_ECLEVEL_Q] = "Q", 31 | [QR_ECLEVEL_H] = "H", 32 | }; 33 | 34 | 35 | void 36 | generate(int version, QRencodeMode mode, QRecLevel level) 37 | { 38 | const char *num_data = "42"; 39 | int num_datalen = strlen(num_data); 40 | const char *an_data = "AC-42"; 41 | int an_datalen = strlen(an_data); 42 | const char *bin_data = "aA1234"; 43 | int bin_datalen = strlen(bin_data); 44 | /* taken from https://github.com/fukuchi/libqrencode/blob/master/tests/test_estimatebit.c#L109 */ 45 | const unsigned char kanji_data[4] = {0x93, 0x5f,0xe4, 0xaa}; /* 点茗 in Shift-JIS */ 46 | int kanji_datalen = sizeof(kanji_data); 47 | const unsigned char *data; 48 | int datalen; 49 | QRinput *input; 50 | QRcode *code; 51 | png_structp png_ptr; 52 | png_infop info_ptr; 53 | int dot_size = 3, margin = 4; 54 | char white = 0xFF, black = 0x00; 55 | char *fn; 56 | FILE *fh; 57 | int x, y, d; 58 | 59 | switch (mode) { 60 | case QR_MODE_NUM: 61 | data = (const unsigned char *)num_data; 62 | datalen = num_datalen; 63 | break; 64 | case QR_MODE_AN: 65 | data = (const unsigned char *)an_data; 66 | datalen = an_datalen; 67 | break; 68 | case QR_MODE_8: 69 | data = (const unsigned char *)bin_data; 70 | datalen = bin_datalen; 71 | break; 72 | case QR_MODE_KANJI: 73 | data = (const unsigned char *)kanji_data; 74 | datalen = kanji_datalen; 75 | break; 76 | default: 77 | errx(1, "%d: unsupported mode", mode); 78 | /* NOTREACHED */ 79 | }; 80 | 81 | input = QRinput_new2(version, level); 82 | if (input == NULL) 83 | err(1, "QRinput_new2"); 84 | if (QRinput_append(input, mode, datalen, data) == -1) 85 | err(1, "QRinput_append"); 86 | code = QRcode_encodeInput(input); 87 | QRinput_free(input); 88 | 89 | int ret = asprintf(&fn, "version=%02d,level=%s,mode=%s.png", 90 | version, ecc_level_str[level], mode_str[mode]); 91 | if (ret == -1) 92 | err(1, "asprintf"); 93 | if ((fh = fopen(fn, "wb")) == NULL) 94 | err(1, "fopen"); 95 | 96 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 97 | if (png_ptr == NULL) 98 | err(1, "png_create_write_struct"); 99 | info_ptr = png_create_info_struct(png_ptr); 100 | if (info_ptr == NULL) 101 | err(1, "png_create_info_struct"); 102 | if (setjmp(png_jmpbuf(png_ptr))) 103 | err(1, "setjmp"); 104 | png_init_io(png_ptr, fh); 105 | png_set_IHDR(png_ptr, info_ptr, 106 | (code->width + margin * 2) * dot_size, 107 | (code->width + margin * 2) * dot_size, 108 | 1 /* depth */, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, 109 | PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 110 | png_write_info(png_ptr, info_ptr); 111 | png_set_packing(png_ptr); 112 | unsigned char *row = calloc((code->width + margin * 2), dot_size); 113 | if (row == NULL) 114 | err(1, "calloc"); 115 | for (y = -margin; y < code->width + margin; y++) { 116 | for (x = -margin; x < code->width + margin; x++) { 117 | unsigned char dot; 118 | if (y < 0 || y > code->width - 1 || x < 0 || x > code->width - 1) 119 | dot = white; 120 | else 121 | dot = (code->data[y * code->width + x] & 0x1 ? black : white); 122 | for (d = 0; d < dot_size; d++) 123 | row[(x + margin) * dot_size + d] = dot; 124 | } 125 | for (d = 0; d < dot_size; d++) 126 | png_write_row(png_ptr, row); 127 | } 128 | 129 | png_write_end(png_ptr, info_ptr); 130 | free(row); 131 | 132 | /* cleanup */ 133 | png_destroy_write_struct(&png_ptr, &info_ptr); 134 | fclose(fh); 135 | QRcode_free(code); 136 | } 137 | 138 | 139 | int 140 | main(int argc, char **argv) 141 | { 142 | for (int version = 1; version <= 40; version++) { 143 | for (QRencodeMode mode = QR_MODE_NUM; mode <= QR_MODE_KANJI; mode++) { 144 | for (QRecLevel level = QR_ECLEVEL_L; level <= QR_ECLEVEL_H; level++) { 145 | (void)printf("version=%02d,level=%s,mode=%s\n", 146 | version, ecc_level_str[level], mode_str[mode]); 147 | generate(version, mode, level); 148 | } 149 | } 150 | } 151 | return (EXIT_SUCCESS); 152 | } 153 | -------------------------------------------------------------------------------- /deps/quirc/quirc.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef QUIRC_H_ 18 | #define QUIRC_H_ 19 | 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | struct quirc; 27 | 28 | /* Obtain the library version string. */ 29 | const char *quirc_version(void); 30 | 31 | /* Construct a new QR-code recognizer. This function will return NULL 32 | * if sufficient memory could not be allocated. 33 | */ 34 | struct quirc *quirc_new(void); 35 | 36 | /* Destroy a QR-code recognizer. */ 37 | void quirc_destroy(struct quirc *q); 38 | 39 | /* Resize the QR-code recognizer. The size of an image must be 40 | * specified before codes can be analyzed. 41 | * 42 | * This function returns 0 on success, or -1 if sufficient memory could 43 | * not be allocated. 44 | */ 45 | int quirc_resize(struct quirc *q, int w, int h); 46 | 47 | /* These functions are used to process images for QR-code recognition. 48 | * quirc_begin() must first be called to obtain access to a buffer into 49 | * which the input image should be placed. Optionally, the current 50 | * width and height may be returned. 51 | * 52 | * After filling the buffer, quirc_end() should be called to process 53 | * the image for QR-code recognition. The locations and content of each 54 | * code may be obtained using accessor functions described below. 55 | */ 56 | uint8_t *quirc_begin(struct quirc *q, int *w, int *h); 57 | void quirc_end(struct quirc *q); 58 | 59 | /* This structure describes a location in the input image buffer. */ 60 | struct quirc_point { 61 | int x; 62 | int y; 63 | }; 64 | 65 | /* This enum describes the various decoder errors which may occur. */ 66 | typedef enum { 67 | QUIRC_SUCCESS = 0, 68 | QUIRC_ERROR_INVALID_GRID_SIZE, 69 | QUIRC_ERROR_INVALID_VERSION, 70 | QUIRC_ERROR_FORMAT_ECC, 71 | QUIRC_ERROR_DATA_ECC, 72 | QUIRC_ERROR_UNKNOWN_DATA_TYPE, 73 | QUIRC_ERROR_DATA_OVERFLOW, 74 | QUIRC_ERROR_DATA_UNDERFLOW 75 | } quirc_decode_error_t; 76 | 77 | /* Return a string error message for an error code. */ 78 | const char *quirc_strerror(quirc_decode_error_t err); 79 | 80 | /* Limits on the maximum size of QR-codes and their content. */ 81 | #define QUIRC_MAX_VERSION 40 82 | #define QUIRC_MAX_GRID_SIZE (QUIRC_MAX_VERSION * 4 + 17) 83 | #define QUIRC_MAX_BITMAP (((QUIRC_MAX_GRID_SIZE * QUIRC_MAX_GRID_SIZE) + 7) / 8) 84 | #define QUIRC_MAX_PAYLOAD 8896 85 | 86 | /* QR-code ECC types. */ 87 | #define QUIRC_ECC_LEVEL_M 0 88 | #define QUIRC_ECC_LEVEL_L 1 89 | #define QUIRC_ECC_LEVEL_H 2 90 | #define QUIRC_ECC_LEVEL_Q 3 91 | 92 | /* QR-code data types. */ 93 | #define QUIRC_DATA_TYPE_NUMERIC 1 94 | #define QUIRC_DATA_TYPE_ALPHA 2 95 | #define QUIRC_DATA_TYPE_BYTE 4 96 | #define QUIRC_DATA_TYPE_KANJI 8 97 | 98 | /* Common character encodings */ 99 | #define QUIRC_ECI_ISO_8859_1 1 100 | #define QUIRC_ECI_IBM437 2 101 | #define QUIRC_ECI_ISO_8859_2 4 102 | #define QUIRC_ECI_ISO_8859_3 5 103 | #define QUIRC_ECI_ISO_8859_4 6 104 | #define QUIRC_ECI_ISO_8859_5 7 105 | #define QUIRC_ECI_ISO_8859_6 8 106 | #define QUIRC_ECI_ISO_8859_7 9 107 | #define QUIRC_ECI_ISO_8859_8 10 108 | #define QUIRC_ECI_ISO_8859_9 11 109 | #define QUIRC_ECI_WINDOWS_874 13 110 | #define QUIRC_ECI_ISO_8859_13 15 111 | #define QUIRC_ECI_ISO_8859_15 17 112 | #define QUIRC_ECI_SHIFT_JIS 20 113 | #define QUIRC_ECI_UTF_8 26 114 | 115 | /* This structure is used to return information about detected QR codes 116 | * in the input image. 117 | */ 118 | struct quirc_code { 119 | /* The four corners of the QR-code, from top left, clockwise */ 120 | struct quirc_point corners[4]; 121 | 122 | /* The number of cells across in the QR-code. The cell bitmap 123 | * is a bitmask giving the actual values of cells. If the cell 124 | * at (x, y) is black, then the following bit is set: 125 | * 126 | * cell_bitmap[i >> 3] & (1 << (i & 7)) 127 | * 128 | * where i = (y * size) + x. 129 | */ 130 | int size; 131 | uint8_t cell_bitmap[QUIRC_MAX_BITMAP]; 132 | }; 133 | 134 | /* This structure holds the decoded QR-code data */ 135 | struct quirc_data { 136 | /* Various parameters of the QR-code. These can mostly be 137 | * ignored if you only care about the data. 138 | */ 139 | int version; 140 | int ecc_level; 141 | int mask; 142 | 143 | /* This field is the highest-valued data type found in the QR 144 | * code. 145 | */ 146 | int data_type; 147 | 148 | /* Data payload. For the Kanji datatype, payload is encoded as 149 | * Shift-JIS. For all other datatypes, payload is ASCII text. 150 | */ 151 | uint8_t payload[QUIRC_MAX_PAYLOAD]; 152 | int payload_len; 153 | 154 | /* ECI assignment number */ 155 | uint32_t eci; 156 | }; 157 | 158 | /* Return the number of QR-codes identified in the last processed 159 | * image. 160 | */ 161 | int quirc_count(const struct quirc *q); 162 | 163 | /* Extract the QR-code specified by the given index. */ 164 | void quirc_extract(const struct quirc *q, int index, 165 | struct quirc_code *code); 166 | 167 | /* Decode a QR-code, returning the payload data. */ 168 | quirc_decode_error_t quirc_decode(const struct quirc_code *code, 169 | struct quirc_data *data); 170 | 171 | /* Flip a QR-code according to optional mirror feature of ISO 18004:2015 */ 172 | void quirc_flip(struct quirc_code *code); 173 | 174 | #ifdef __cplusplus 175 | } 176 | #endif 177 | 178 | #endif 179 | -------------------------------------------------------------------------------- /src/node-quirc.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * node-quirc.cc - glue for Node.js 3 | */ 4 | 5 | #include 6 | 7 | extern "C" { 8 | #include "node_quirc_decode.h" 9 | } 10 | 11 | using Nan::AsyncQueueWorker; 12 | using Nan::AsyncWorker; 13 | using Nan::Callback; 14 | using Nan::CopyBuffer; 15 | using Nan::Error; 16 | using Nan::GetFunction; 17 | using Nan::New; 18 | using Nan::Null; 19 | using Nan::Set; 20 | using Nan::ThrowError; 21 | using Nan::ThrowTypeError; 22 | 23 | /* async worker wrapper around nq_decode() */ 24 | class NodeQuircDecoder: public AsyncWorker 25 | { 26 | public: 27 | 28 | /* ctor */ 29 | NodeQuircDecoder(Callback *callback, const uint8_t *img, size_t img_len, size_t img_width, size_t img_height): 30 | AsyncWorker(callback), 31 | m_img(img), 32 | m_img_len(img_len), 33 | m_img_width(img_width), 34 | m_img_height(img_height), 35 | m_code_list(NULL) 36 | { } 37 | 38 | 39 | /* dtor */ 40 | ~NodeQuircDecoder() 41 | { 42 | nq_code_list_free(m_code_list); 43 | } 44 | 45 | 46 | // Executed inside the worker-thread. 47 | // It is not safe to access V8, or V8 data structures here, so 48 | // everything we need for input and output should go on `this`. 49 | void Execute() 50 | { 51 | m_code_list = nq_decode(m_img, m_img_len, m_img_width, m_img_height); 52 | } 53 | 54 | 55 | // Executed when the async work is complete this function will be run 56 | // inside the main event loop so it is safe to use V8 again 57 | void HandleOKCallback() 58 | { 59 | /* ENOMEM check */ 60 | if (m_code_list == NULL) 61 | return ThrowError("Could not allocate memory"); 62 | 63 | /* global error check */ 64 | if (nq_code_list_err(m_code_list) != NULL) 65 | return CallbackError(nq_code_list_err(m_code_list)); 66 | 67 | unsigned int count = nq_code_list_size(m_code_list); 68 | v8::Local results = New(); 69 | for (unsigned int i = 0; i < count; i++) { 70 | const struct nq_code *code = nq_code_at(m_code_list, i); 71 | Nan::Maybe success = Set(results, i, CodeToObject(code)); 72 | if (success.IsNothing() || !success.FromJust()) 73 | return CallbackError("Set() failed"); 74 | } 75 | 76 | // all went well 77 | v8::Local argv[] = { 78 | Null(), /* err */ 79 | results, 80 | }; 81 | Nan::Call(*callback, 2, argv); 82 | } 83 | 84 | 85 | private: 86 | 87 | /* members */ 88 | 89 | /* nq_decode() arguments */ 90 | const uint8_t *m_img; 91 | size_t m_img_len; 92 | size_t m_img_width; 93 | size_t m_img_height; 94 | /* nq_decode() return value */ 95 | struct nq_code_list *m_code_list; 96 | 97 | /* helpers */ 98 | 99 | // call `callback` with an Error containing msg. 100 | void CallbackError(const char *msg) 101 | { 102 | v8::Local argv[] = { 103 | Error(msg), 104 | }; 105 | Nan::Call(*callback, 1, argv); 106 | } 107 | 108 | 109 | // "convert" a struct nq_code to a v8::Object 110 | v8::Local CodeToObject(const struct nq_code *code) 111 | { 112 | v8::Local obj = New(); 113 | if (nq_code_err(code) != NULL) { 114 | Set(obj, New("err").ToLocalChecked(), 115 | New(nq_code_err(code)).ToLocalChecked()); 116 | } else { 117 | Set(obj, New("version").ToLocalChecked(), 118 | New(nq_code_version(code))); 119 | Set(obj, New("ecc_level").ToLocalChecked(), 120 | New(nq_code_ecc_level_str(code)).ToLocalChecked()); 121 | Set(obj, New("mask").ToLocalChecked(), 122 | New(nq_code_mask(code))); 123 | Set(obj, New("mode").ToLocalChecked(), 124 | New(nq_code_mode_str(code)).ToLocalChecked()); 125 | const char *eci = nq_code_eci_str(code); 126 | if (eci) { 127 | Set(obj, New("eci").ToLocalChecked(), 128 | New(eci).ToLocalChecked()); 129 | } 130 | const char *data = (const char *)nq_code_payload(code); 131 | Set(obj, New("data").ToLocalChecked(), 132 | CopyBuffer(data, nq_code_payload_len(code)).ToLocalChecked()); 133 | } 134 | return (obj); 135 | } 136 | }; 137 | 138 | 139 | // async access to nq_decode() 140 | NAN_METHOD(NodeQuircDecodeEncodedAsync) { 141 | if (info.Length() < 2) 142 | return ThrowError("expected (img, callback) as arguments"); 143 | if (!node::Buffer::HasInstance(info[0])) 144 | return ThrowTypeError("img must be a Buffer"); 145 | if (!info[1]->IsFunction()) 146 | return ThrowTypeError("callback must be a function"); 147 | 148 | uint8_t *img = (uint8_t *)node::Buffer::Data(info[0]); 149 | size_t img_len = node::Buffer::Length(info[0]); 150 | Callback *callback = new Callback(info[1].As()); 151 | AsyncQueueWorker(new NodeQuircDecoder(callback, img, img_len, 0, 0)); 152 | } 153 | 154 | NAN_METHOD(NodeQuircDecodeRawAsync) { 155 | if (info.Length() < 4) 156 | return ThrowError("expected (pixels, width, height, callback) as arguments"); 157 | // Uint8ClampedArray is from ImageData#data, Buffer is allowed for convenience. 158 | if (!info[0]->IsUint8ClampedArray() && !node::Buffer::HasInstance(info[0])) 159 | return ThrowTypeError("pixels must be a Uint8ClampedArray or Buffer"); 160 | if (!info[1]->IsNumber()) 161 | return ThrowTypeError("width must be a number"); 162 | if (!info[2]->IsNumber()) 163 | return ThrowTypeError("height must be a number"); 164 | if (!info[3]->IsFunction()) 165 | return ThrowTypeError("callback must be a function"); 166 | 167 | uint8_t *img; 168 | size_t img_len; 169 | 170 | if (node::Buffer::HasInstance(info[0])) { 171 | img = (uint8_t *)node::Buffer::Data(info[0]); 172 | img_len = node::Buffer::Length(info[0]); 173 | } else { 174 | Nan::TypedArrayContents data(info[0]); 175 | img = *data; 176 | img_len = data.length(); 177 | } 178 | 179 | size_t img_width = (size_t)Nan::To(info[1]).FromJust(); 180 | size_t img_height = (size_t)Nan::To(info[2]).FromJust(); 181 | Callback *callback = new Callback(info[3].As()); 182 | AsyncQueueWorker(new NodeQuircDecoder(callback, img, img_len, img_width, img_height)); 183 | } 184 | 185 | // export stuff to NodeJS 186 | NAN_MODULE_INIT(NodeQuircInit) { 187 | Set(target, New("decodeEncoded").ToLocalChecked(), 188 | GetFunction(New(NodeQuircDecodeEncodedAsync)).ToLocalChecked()); 189 | Set(target, New("decodeRaw").ToLocalChecked(), 190 | GetFunction(New(NodeQuircDecodeRawAsync)).ToLocalChecked()); 191 | } 192 | 193 | 194 | NODE_MODULE(node_quirc, NodeQuircInit) 195 | -------------------------------------------------------------------------------- /src/node_quirc_decode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * node_quirc_decode.c - node-quirc decoding stuff 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #define PNG_BYTES_TO_CHECK 4 11 | #include 12 | 13 | #include "node_quirc_decode.h" 14 | #include "quirc.h" 15 | 16 | 17 | /* a nq_code list */ 18 | struct nq_code_list { 19 | const char *err; /* global error */ 20 | struct nq_code *codes; 21 | unsigned int size; 22 | }; 23 | 24 | struct nq_code { 25 | const char *err; 26 | struct quirc_code qcode; 27 | struct quirc_data qdata; 28 | }; 29 | 30 | static int nq_load_image(struct quirc *q, const uint8_t *img, size_t img_len, size_t img_width, size_t img_height); 31 | static int nq_load_png(struct quirc *q, const uint8_t *img, size_t img_len); 32 | static int nq_load_jpeg(struct quirc *q, const uint8_t *img, size_t img_len); 33 | static int nq_load_raw(struct quirc *q, const uint8_t *img, size_t img_len, size_t img_width, size_t img_height); 34 | 35 | 36 | struct nq_code_list * 37 | nq_decode(const uint8_t *img, size_t img_len, size_t img_width, size_t img_height) 38 | { 39 | struct nq_code_list *list = NULL; 40 | struct quirc *q = NULL; 41 | 42 | list = calloc(1, sizeof(struct nq_code_list)); 43 | if (list == NULL) 44 | goto out; 45 | 46 | q = quirc_new(); 47 | if (q == NULL) { 48 | list->err = "quirc_new()"; 49 | goto out; 50 | } 51 | 52 | if (nq_load_image(q, img, img_len, img_width, img_height) == -1) { 53 | // FIXME: more descriptive error here? 54 | list->err = "failed to load image"; 55 | goto out; 56 | } 57 | 58 | quirc_end(q); 59 | 60 | int count = quirc_count(q); 61 | if (count < 0) { 62 | list->err = "quirc_count()"; 63 | goto out; 64 | } 65 | 66 | list->size = (unsigned int)count; 67 | list->codes = calloc((size_t)list->size, sizeof(struct nq_code)); 68 | if (list->codes == NULL) { 69 | nq_code_list_free(list); 70 | list = NULL; 71 | goto out; 72 | } 73 | 74 | for (int i = 0; i < count; i++) { 75 | struct nq_code *nqcode = list->codes + i; 76 | quirc_decode_error_t err; 77 | 78 | quirc_extract(q, i, &nqcode->qcode); 79 | err = quirc_decode(&nqcode->qcode, &nqcode->qdata); 80 | if (err == QUIRC_ERROR_DATA_ECC) { 81 | quirc_flip(&nqcode->qcode); 82 | err = quirc_decode(&nqcode->qcode, &nqcode->qdata); 83 | } 84 | 85 | if (err) 86 | nqcode->err = quirc_strerror(err); 87 | } 88 | 89 | /* FALLTHROUGH */ 90 | out: 91 | /* cleanup */ 92 | if (q != NULL) 93 | quirc_destroy(q); 94 | 95 | return (list); 96 | } 97 | 98 | 99 | const char * 100 | nq_code_list_err(const struct nq_code_list *list) 101 | { 102 | return (list->err); 103 | } 104 | 105 | 106 | unsigned int 107 | nq_code_list_size(const struct nq_code_list *list) 108 | { 109 | return (list->size); 110 | } 111 | 112 | 113 | const struct nq_code * 114 | nq_code_at(const struct nq_code_list *list, unsigned int index) 115 | { 116 | const struct nq_code *target = NULL; 117 | 118 | if (index < nq_code_list_size(list)) 119 | target = list->codes + index; 120 | 121 | return (target); 122 | 123 | } 124 | 125 | 126 | void 127 | nq_code_list_free(struct nq_code_list *list) 128 | { 129 | if (list != NULL) 130 | free(list->codes); 131 | free(list); 132 | } 133 | 134 | 135 | const char * 136 | nq_code_err(const struct nq_code *code) 137 | { 138 | return (code->err); 139 | } 140 | 141 | 142 | int 143 | nq_code_version(const struct nq_code *code) 144 | { 145 | return (code->qdata.version); 146 | } 147 | 148 | 149 | const char * 150 | nq_code_ecc_level_str(const struct nq_code *code) 151 | { 152 | switch (code->qdata.ecc_level) { 153 | case QUIRC_ECC_LEVEL_M: return "M"; 154 | case QUIRC_ECC_LEVEL_L: return "L"; 155 | case QUIRC_ECC_LEVEL_H: return "H"; 156 | case QUIRC_ECC_LEVEL_Q: return "Q"; 157 | } 158 | 159 | return "?"; 160 | } 161 | 162 | 163 | int 164 | nq_code_mask(const struct nq_code *code) 165 | { 166 | return (code->qdata.mask); 167 | } 168 | 169 | 170 | const char * 171 | nq_code_mode_str(const struct nq_code *code) 172 | { 173 | switch (code->qdata.data_type) { 174 | case QUIRC_DATA_TYPE_NUMERIC: return "NUMERIC"; 175 | case QUIRC_DATA_TYPE_ALPHA: return "ALNUM"; 176 | case QUIRC_DATA_TYPE_BYTE: return "BYTE"; 177 | case QUIRC_DATA_TYPE_KANJI: return "KANJI"; 178 | } 179 | 180 | return "unknown"; 181 | } 182 | 183 | 184 | const char * 185 | nq_code_eci_str(const struct nq_code *code) 186 | { 187 | switch (code->qdata.eci) { 188 | case QUIRC_ECI_ISO_8859_1: return "ISO_8859_1"; 189 | case QUIRC_ECI_IBM437: return "IBM437"; 190 | case QUIRC_ECI_ISO_8859_2: return "ISO_8859_2"; 191 | case QUIRC_ECI_ISO_8859_3: return "ISO_8859_3"; 192 | case QUIRC_ECI_ISO_8859_4: return "ISO_8859_4"; 193 | case QUIRC_ECI_ISO_8859_5: return "ISO_8859_5"; 194 | case QUIRC_ECI_ISO_8859_6: return "ISO_8859_6"; 195 | case QUIRC_ECI_ISO_8859_7: return "ISO_8859_7"; 196 | case QUIRC_ECI_ISO_8859_8: return "ISO_8859_8"; 197 | case QUIRC_ECI_ISO_8859_9: return "ISO_8859_9"; 198 | case QUIRC_ECI_WINDOWS_874: return "WINDOWS_874"; 199 | case QUIRC_ECI_ISO_8859_13: return "ISO_8859_13"; 200 | case QUIRC_ECI_ISO_8859_15: return "ISO_8859_15"; 201 | case QUIRC_ECI_SHIFT_JIS: return "SHIFT_JIS"; 202 | case QUIRC_ECI_UTF_8: return "UTF_8"; 203 | } 204 | return NULL; 205 | } 206 | 207 | 208 | const uint8_t * 209 | nq_code_payload(const struct nq_code *code) 210 | { 211 | return (code->qdata.payload); 212 | } 213 | 214 | 215 | size_t 216 | nq_code_payload_len(const struct nq_code *code) 217 | { 218 | return (code->qdata.payload_len); 219 | } 220 | 221 | 222 | /* returns 0 on success, -1 on error */ 223 | static int 224 | nq_load_image(struct quirc *q, const uint8_t *img, size_t img_len, size_t img_width, size_t img_height) 225 | { 226 | if (img_width > 0 && img_height > 0) { 227 | return nq_load_raw(q, img, img_len, img_width, img_height); 228 | } 229 | 230 | int ret = -1; /* error */ 231 | 232 | if (img_len >= PNG_BYTES_TO_CHECK) { 233 | if (png_sig_cmp((uint8_t *)img, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0) 234 | ret = nq_load_png(q, img, img_len); 235 | } 236 | 237 | if (ret != 0) { 238 | ret = nq_load_jpeg(q, img, img_len); 239 | } 240 | 241 | return (ret); 242 | } 243 | 244 | 245 | /* hacked from quirc/tests/dbgutil.c */ 246 | static int 247 | nq_load_png(struct quirc *q, const uint8_t *img, size_t img_len) 248 | { 249 | int width, height, rowbytes, interlace_type, number_passes = 1; 250 | png_uint_32 trns; 251 | png_byte color_type, bit_depth; 252 | png_structp png_ptr = NULL; 253 | png_infop info_ptr = NULL; 254 | uint8_t *image; 255 | FILE *infile = NULL; 256 | volatile int success = 0; 257 | 258 | infile = fmemopen((uint8_t *)img, img_len, "r"); 259 | if (infile == NULL) 260 | goto out; 261 | 262 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 263 | if (png_ptr == NULL) 264 | goto out; 265 | 266 | info_ptr = png_create_info_struct(png_ptr); 267 | if (info_ptr == NULL) 268 | goto out; 269 | 270 | if (setjmp(png_jmpbuf(png_ptr))) 271 | goto out; 272 | 273 | png_init_io(png_ptr, infile); 274 | 275 | png_read_info(png_ptr, info_ptr); 276 | 277 | color_type = png_get_color_type(png_ptr, info_ptr); 278 | bit_depth = png_get_bit_depth(png_ptr, info_ptr); 279 | interlace_type = png_get_interlace_type(png_ptr, info_ptr); 280 | 281 | // Read any color_type into 8bit depth, Grayscale format. 282 | // See http://www.libpng.org/pub/png/libpng-manual.txt 283 | 284 | // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. 285 | if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) 286 | png_set_expand_gray_1_2_4_to_8(png_ptr); 287 | 288 | if ((trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) 289 | png_set_tRNS_to_alpha(png_ptr); 290 | 291 | if (bit_depth == 16) 292 | #if PNG_LIBPNG_VER >= 10504 293 | png_set_scale_16(png_ptr); 294 | #else 295 | png_set_strip_16(png_ptr); 296 | #endif 297 | 298 | if ((trns) || color_type & PNG_COLOR_MASK_ALPHA) 299 | png_set_strip_alpha(png_ptr); 300 | 301 | if (color_type == PNG_COLOR_TYPE_PALETTE) 302 | png_set_palette_to_rgb(png_ptr); 303 | 304 | if (color_type == PNG_COLOR_TYPE_PALETTE || 305 | color_type == PNG_COLOR_TYPE_RGB || 306 | color_type == PNG_COLOR_TYPE_RGB_ALPHA) { 307 | png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1); 308 | } 309 | 310 | if (interlace_type != PNG_INTERLACE_NONE) 311 | number_passes = png_set_interlace_handling(png_ptr); 312 | 313 | png_read_update_info(png_ptr, info_ptr); 314 | 315 | width = png_get_image_width(png_ptr, info_ptr); 316 | height = png_get_image_height(png_ptr, info_ptr); 317 | rowbytes = png_get_rowbytes(png_ptr, info_ptr); 318 | if (rowbytes != width) { 319 | goto out; 320 | } 321 | 322 | if (quirc_resize(q, width, height) < 0) 323 | goto out; 324 | 325 | image = quirc_begin(q, NULL, NULL); 326 | 327 | for (int pass = 0; pass < number_passes; pass++) { 328 | int y; 329 | 330 | for (y = 0; y < height; y++) { 331 | png_bytep row_pointer = image + y * width; 332 | png_read_rows(png_ptr, &row_pointer, NULL, 1); 333 | } 334 | } 335 | 336 | png_read_end(png_ptr, info_ptr); 337 | 338 | success = 1; 339 | /* FALLTHROUGH */ 340 | out: 341 | /* cleanup */ 342 | if (png_ptr != NULL) { 343 | if (info_ptr != NULL) 344 | png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 345 | else 346 | png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); 347 | } 348 | if (infile != NULL) 349 | fclose(infile); 350 | return (success ? 0 : -1); 351 | } 352 | 353 | 354 | /* hacked from quirc/tests/dbgutil.c */ 355 | struct nq_jpeg_error { 356 | struct jpeg_error_mgr base; 357 | jmp_buf env; 358 | }; 359 | 360 | 361 | static void 362 | nq_error_exit(struct jpeg_common_struct *com) 363 | { 364 | struct nq_jpeg_error *err = (struct nq_jpeg_error *)com->err; 365 | 366 | longjmp(err->env, 0); 367 | } 368 | 369 | 370 | static struct jpeg_error_mgr * 371 | nq_error_mgr(struct nq_jpeg_error *err) 372 | { 373 | jpeg_std_error(&err->base); 374 | err->base.error_exit = nq_error_exit; 375 | return &err->base; 376 | } 377 | 378 | 379 | static int 380 | nq_load_jpeg(struct quirc *q, const uint8_t *img, size_t img_len) 381 | { 382 | struct jpeg_decompress_struct dinfo; 383 | struct nq_jpeg_error err; 384 | uint8_t *image; 385 | JDIMENSION y; 386 | 387 | memset(&dinfo, 0, sizeof(dinfo)); 388 | dinfo.err = nq_error_mgr(&err); 389 | 390 | if (setjmp(err.env)) 391 | goto fail; 392 | 393 | jpeg_create_decompress(&dinfo); 394 | jpeg_mem_src(&dinfo, img, img_len); 395 | 396 | jpeg_read_header(&dinfo, TRUE); 397 | dinfo.output_components = 1; 398 | dinfo.out_color_space = JCS_GRAYSCALE; 399 | jpeg_start_decompress(&dinfo); 400 | 401 | if (dinfo.output_components != 1) 402 | goto fail; 403 | 404 | if (quirc_resize(q, dinfo.output_width, dinfo.output_height) < 0) 405 | goto fail; 406 | 407 | image = quirc_begin(q, NULL, NULL); 408 | 409 | for (y = 0; y < dinfo.output_height; y++) 410 | { 411 | JSAMPROW row_pointer = image + y * dinfo.output_width; 412 | 413 | jpeg_read_scanlines(&dinfo, &row_pointer, 1); 414 | } 415 | 416 | jpeg_finish_decompress(&dinfo); 417 | jpeg_destroy_decompress(&dinfo); 418 | return 0; 419 | 420 | fail: 421 | jpeg_destroy_decompress(&dinfo); 422 | return -1; 423 | } 424 | 425 | static int 426 | nq_load_raw(struct quirc *q, const uint8_t *img, size_t img_len, size_t img_width, size_t img_height) 427 | { 428 | if (quirc_resize(q, img_width, img_height) < 0) 429 | goto fail; 430 | 431 | uint8_t *image = quirc_begin(q, NULL, NULL); 432 | 433 | const size_t len = img_width * img_height; 434 | const int channels = len == img_len ? 1 : /* grayscale */ 435 | 3 * len == img_len ? 3 : /* rgb */ 436 | 4 * len == img_len ? 4 : /* rgba */ 437 | /* default */ -1; 438 | 439 | if (channels == 1) { 440 | memcpy(image, img, img_len); 441 | } else if (channels == 3 || channels == 4) { 442 | for ( 443 | size_t dst_offset = 0, src_offset = 0; 444 | dst_offset < img_width * img_height; 445 | dst_offset++, src_offset += channels 446 | ) { 447 | uint8_t r = img[src_offset]; 448 | uint8_t g = img[src_offset + 1]; 449 | uint8_t b = img[src_offset + 2]; 450 | // convert RGB to grayscale, ignoring alpha channel if present, using this: 451 | // https://en.wikipedia.org/wiki/Grayscale#Colorimetric_(perceptual_luminance-preserving)_conversion_to_grayscale 452 | image[dst_offset] = (uint8_t)(0.2126 * (float)r + 0.7152 * (float)g + 0.0722 * (float)b); 453 | } 454 | } else { 455 | goto fail; 456 | } 457 | 458 | return 0; 459 | 460 | fail: 461 | return -1; 462 | } 463 | -------------------------------------------------------------------------------- /deps/quirc/version_db.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "quirc_internal.h" 18 | 19 | const struct quirc_version_info quirc_version_db[QUIRC_MAX_VERSION + 1] = { 20 | {0}, 21 | { /* Version 1 */ 22 | .data_bytes = 26, 23 | .apat = {0}, 24 | .ecc = { 25 | {.bs = 26, .dw = 16, .ns = 1}, 26 | {.bs = 26, .dw = 19, .ns = 1}, 27 | {.bs = 26, .dw = 9, .ns = 1}, 28 | {.bs = 26, .dw = 13, .ns = 1} 29 | } 30 | }, 31 | { /* Version 2 */ 32 | .data_bytes = 44, 33 | .apat = {6, 18, 0}, 34 | .ecc = { 35 | {.bs = 44, .dw = 28, .ns = 1}, 36 | {.bs = 44, .dw = 34, .ns = 1}, 37 | {.bs = 44, .dw = 16, .ns = 1}, 38 | {.bs = 44, .dw = 22, .ns = 1} 39 | } 40 | }, 41 | { /* Version 3 */ 42 | .data_bytes = 70, 43 | .apat = {6, 22, 0}, 44 | .ecc = { 45 | {.bs = 70, .dw = 44, .ns = 1}, 46 | {.bs = 70, .dw = 55, .ns = 1}, 47 | {.bs = 35, .dw = 13, .ns = 2}, 48 | {.bs = 35, .dw = 17, .ns = 2} 49 | } 50 | }, 51 | { /* Version 4 */ 52 | .data_bytes = 100, 53 | .apat = {6, 26, 0}, 54 | .ecc = { 55 | {.bs = 50, .dw = 32, .ns = 2}, 56 | {.bs = 100, .dw = 80, .ns = 1}, 57 | {.bs = 25, .dw = 9, .ns = 4}, 58 | {.bs = 50, .dw = 24, .ns = 2} 59 | } 60 | }, 61 | { /* Version 5 */ 62 | .data_bytes = 134, 63 | .apat = {6, 30, 0}, 64 | .ecc = { 65 | {.bs = 67, .dw = 43, .ns = 2}, 66 | {.bs = 134, .dw = 108, .ns = 1}, 67 | {.bs = 33, .dw = 11, .ns = 2}, 68 | {.bs = 33, .dw = 15, .ns = 2} 69 | } 70 | }, 71 | { /* Version 6 */ 72 | .data_bytes = 172, 73 | .apat = {6, 34, 0}, 74 | .ecc = { 75 | {.bs = 43, .dw = 27, .ns = 4}, 76 | {.bs = 86, .dw = 68, .ns = 2}, 77 | {.bs = 43, .dw = 15, .ns = 4}, 78 | {.bs = 43, .dw = 19, .ns = 4} 79 | } 80 | }, 81 | { /* Version 7 */ 82 | .data_bytes = 196, 83 | .apat = {6, 22, 38, 0}, 84 | .ecc = { 85 | {.bs = 49, .dw = 31, .ns = 4}, 86 | {.bs = 98, .dw = 78, .ns = 2}, 87 | {.bs = 39, .dw = 13, .ns = 4}, 88 | {.bs = 32, .dw = 14, .ns = 2} 89 | } 90 | }, 91 | { /* Version 8 */ 92 | .data_bytes = 242, 93 | .apat = {6, 24, 42, 0}, 94 | .ecc = { 95 | {.bs = 60, .dw = 38, .ns = 2}, 96 | {.bs = 121, .dw = 97, .ns = 2}, 97 | {.bs = 40, .dw = 14, .ns = 4}, 98 | {.bs = 40, .dw = 18, .ns = 4} 99 | } 100 | }, 101 | { /* Version 9 */ 102 | .data_bytes = 292, 103 | .apat = {6, 26, 46, 0}, 104 | .ecc = { 105 | {.bs = 58, .dw = 36, .ns = 3}, 106 | {.bs = 146, .dw = 116, .ns = 2}, 107 | {.bs = 36, .dw = 12, .ns = 4}, 108 | {.bs = 36, .dw = 16, .ns = 4} 109 | } 110 | }, 111 | { /* Version 10 */ 112 | .data_bytes = 346, 113 | .apat = {6, 28, 50, 0}, 114 | .ecc = { 115 | {.bs = 69, .dw = 43, .ns = 4}, 116 | {.bs = 86, .dw = 68, .ns = 2}, 117 | {.bs = 43, .dw = 15, .ns = 6}, 118 | {.bs = 43, .dw = 19, .ns = 6} 119 | } 120 | }, 121 | { /* Version 11 */ 122 | .data_bytes = 404, 123 | .apat = {6, 30, 54, 0}, 124 | .ecc = { 125 | {.bs = 80, .dw = 50, .ns = 1}, 126 | {.bs = 101, .dw = 81, .ns = 4}, 127 | {.bs = 36, .dw = 12, .ns = 3}, 128 | {.bs = 50, .dw = 22, .ns = 4} 129 | } 130 | }, 131 | { /* Version 12 */ 132 | .data_bytes = 466, 133 | .apat = {6, 32, 58, 0}, 134 | .ecc = { 135 | {.bs = 58, .dw = 36, .ns = 6}, 136 | {.bs = 116, .dw = 92, .ns = 2}, 137 | {.bs = 42, .dw = 14, .ns = 7}, 138 | {.bs = 46, .dw = 20, .ns = 4} 139 | } 140 | }, 141 | { /* Version 13 */ 142 | .data_bytes = 532, 143 | .apat = {6, 34, 62, 0}, 144 | .ecc = { 145 | {.bs = 59, .dw = 37, .ns = 8}, 146 | {.bs = 133, .dw = 107, .ns = 4}, 147 | {.bs = 33, .dw = 11, .ns = 12}, 148 | {.bs = 44, .dw = 20, .ns = 8} 149 | } 150 | }, 151 | { /* Version 14 */ 152 | .data_bytes = 581, 153 | .apat = {6, 26, 46, 66, 0}, 154 | .ecc = { 155 | {.bs = 64, .dw = 40, .ns = 4}, 156 | {.bs = 145, .dw = 115, .ns = 3}, 157 | {.bs = 36, .dw = 12, .ns = 11}, 158 | {.bs = 36, .dw = 16, .ns = 11} 159 | } 160 | }, 161 | { /* Version 15 */ 162 | .data_bytes = 655, 163 | .apat = {6, 26, 48, 70, 0}, 164 | .ecc = { 165 | {.bs = 65, .dw = 41, .ns = 5}, 166 | {.bs = 109, .dw = 87, .ns = 5}, 167 | {.bs = 36, .dw = 12, .ns = 11}, 168 | {.bs = 54, .dw = 24, .ns = 5} 169 | } 170 | }, 171 | { /* Version 16 */ 172 | .data_bytes = 733, 173 | .apat = {6, 26, 50, 74, 0}, 174 | .ecc = { 175 | {.bs = 73, .dw = 45, .ns = 7}, 176 | {.bs = 122, .dw = 98, .ns = 5}, 177 | {.bs = 45, .dw = 15, .ns = 3}, 178 | {.bs = 43, .dw = 19, .ns = 15} 179 | } 180 | }, 181 | { /* Version 17 */ 182 | .data_bytes = 815, 183 | .apat = {6, 30, 54, 78, 0}, 184 | .ecc = { 185 | {.bs = 74, .dw = 46, .ns = 10}, 186 | {.bs = 135, .dw = 107, .ns = 1}, 187 | {.bs = 42, .dw = 14, .ns = 2}, 188 | {.bs = 50, .dw = 22, .ns = 1} 189 | } 190 | }, 191 | { /* Version 18 */ 192 | .data_bytes = 901, 193 | .apat = {6, 30, 56, 82, 0}, 194 | .ecc = { 195 | {.bs = 69, .dw = 43, .ns = 9}, 196 | {.bs = 150, .dw = 120, .ns = 5}, 197 | {.bs = 42, .dw = 14, .ns = 2}, 198 | {.bs = 50, .dw = 22, .ns = 17} 199 | } 200 | }, 201 | { /* Version 19 */ 202 | .data_bytes = 991, 203 | .apat = {6, 30, 58, 86, 0}, 204 | .ecc = { 205 | {.bs = 70, .dw = 44, .ns = 3}, 206 | {.bs = 141, .dw = 113, .ns = 3}, 207 | {.bs = 39, .dw = 13, .ns = 9}, 208 | {.bs = 47, .dw = 21, .ns = 17} 209 | } 210 | }, 211 | { /* Version 20 */ 212 | .data_bytes = 1085, 213 | .apat = {6, 34, 62, 90, 0}, 214 | .ecc = { 215 | {.bs = 67, .dw = 41, .ns = 3}, 216 | {.bs = 135, .dw = 107, .ns = 3}, 217 | {.bs = 43, .dw = 15, .ns = 15}, 218 | {.bs = 54, .dw = 24, .ns = 15} 219 | } 220 | }, 221 | { /* Version 21 */ 222 | .data_bytes = 1156, 223 | .apat = {6, 28, 50, 72, 92, 0}, 224 | .ecc = { 225 | {.bs = 68, .dw = 42, .ns = 17}, 226 | {.bs = 144, .dw = 116, .ns = 4}, 227 | {.bs = 46, .dw = 16, .ns = 19}, 228 | {.bs = 50, .dw = 22, .ns = 17} 229 | } 230 | }, 231 | { /* Version 22 */ 232 | .data_bytes = 1258, 233 | .apat = {6, 26, 50, 74, 98, 0}, 234 | .ecc = { 235 | {.bs = 74, .dw = 46, .ns = 17}, 236 | {.bs = 139, .dw = 111, .ns = 2}, 237 | {.bs = 37, .dw = 13, .ns = 34}, 238 | {.bs = 54, .dw = 24, .ns = 7} 239 | } 240 | }, 241 | { /* Version 23 */ 242 | .data_bytes = 1364, 243 | .apat = {6, 30, 54, 78, 102, 0}, 244 | .ecc = { 245 | {.bs = 75, .dw = 47, .ns = 4}, 246 | {.bs = 151, .dw = 121, .ns = 4}, 247 | {.bs = 45, .dw = 15, .ns = 16}, 248 | {.bs = 54, .dw = 24, .ns = 11} 249 | } 250 | }, 251 | { /* Version 24 */ 252 | .data_bytes = 1474, 253 | .apat = {6, 28, 54, 80, 106, 0}, 254 | .ecc = { 255 | {.bs = 73, .dw = 45, .ns = 6}, 256 | {.bs = 147, .dw = 117, .ns = 6}, 257 | {.bs = 46, .dw = 16, .ns = 30}, 258 | {.bs = 54, .dw = 24, .ns = 11} 259 | } 260 | }, 261 | { /* Version 25 */ 262 | .data_bytes = 1588, 263 | .apat = {6, 32, 58, 84, 110, 0}, 264 | .ecc = { 265 | {.bs = 75, .dw = 47, .ns = 8}, 266 | {.bs = 132, .dw = 106, .ns = 8}, 267 | {.bs = 45, .dw = 15, .ns = 22}, 268 | {.bs = 54, .dw = 24, .ns = 7} 269 | } 270 | }, 271 | { /* Version 26 */ 272 | .data_bytes = 1706, 273 | .apat = {6, 30, 58, 86, 114, 0}, 274 | .ecc = { 275 | {.bs = 74, .dw = 46, .ns = 19}, 276 | {.bs = 142, .dw = 114, .ns = 10}, 277 | {.bs = 46, .dw = 16, .ns = 33}, 278 | {.bs = 50, .dw = 22, .ns = 28} 279 | } 280 | }, 281 | { /* Version 27 */ 282 | .data_bytes = 1828, 283 | .apat = {6, 34, 62, 90, 118, 0}, 284 | .ecc = { 285 | {.bs = 73, .dw = 45, .ns = 22}, 286 | {.bs = 152, .dw = 122, .ns = 8}, 287 | {.bs = 45, .dw = 15, .ns = 12}, 288 | {.bs = 53, .dw = 23, .ns = 8} 289 | } 290 | }, 291 | { /* Version 28 */ 292 | .data_bytes = 1921, 293 | .apat = {6, 26, 50, 74, 98, 122, 0}, 294 | .ecc = { 295 | {.bs = 73, .dw = 45, .ns = 3}, 296 | {.bs = 147, .dw = 117, .ns = 3}, 297 | {.bs = 45, .dw = 15, .ns = 11}, 298 | {.bs = 54, .dw = 24, .ns = 4} 299 | } 300 | }, 301 | { /* Version 29 */ 302 | .data_bytes = 2051, 303 | .apat = {6, 30, 54, 78, 102, 126, 0}, 304 | .ecc = { 305 | {.bs = 73, .dw = 45, .ns = 21}, 306 | {.bs = 146, .dw = 116, .ns = 7}, 307 | {.bs = 45, .dw = 15, .ns = 19}, 308 | {.bs = 53, .dw = 23, .ns = 1} 309 | } 310 | }, 311 | { /* Version 30 */ 312 | .data_bytes = 2185, 313 | .apat = {6, 26, 52, 78, 104, 130, 0}, 314 | .ecc = { 315 | {.bs = 75, .dw = 47, .ns = 19}, 316 | {.bs = 145, .dw = 115, .ns = 5}, 317 | {.bs = 45, .dw = 15, .ns = 23}, 318 | {.bs = 54, .dw = 24, .ns = 15} 319 | } 320 | }, 321 | { /* Version 31 */ 322 | .data_bytes = 2323, 323 | .apat = {6, 30, 56, 82, 108, 134, 0}, 324 | .ecc = { 325 | {.bs = 74, .dw = 46, .ns = 2}, 326 | {.bs = 145, .dw = 115, .ns = 13}, 327 | {.bs = 45, .dw = 15, .ns = 23}, 328 | {.bs = 54, .dw = 24, .ns = 42} 329 | } 330 | }, 331 | { /* Version 32 */ 332 | .data_bytes = 2465, 333 | .apat = {6, 34, 60, 86, 112, 138, 0}, 334 | .ecc = { 335 | {.bs = 74, .dw = 46, .ns = 10}, 336 | {.bs = 145, .dw = 115, .ns = 17}, 337 | {.bs = 45, .dw = 15, .ns = 19}, 338 | {.bs = 54, .dw = 24, .ns = 10} 339 | } 340 | }, 341 | { /* Version 33 */ 342 | .data_bytes = 2611, 343 | .apat = {6, 30, 58, 86, 114, 142, 0}, 344 | .ecc = { 345 | {.bs = 74, .dw = 46, .ns = 14}, 346 | {.bs = 145, .dw = 115, .ns = 17}, 347 | {.bs = 45, .dw = 15, .ns = 11}, 348 | {.bs = 54, .dw = 24, .ns = 29} 349 | } 350 | }, 351 | { /* Version 34 */ 352 | .data_bytes = 2761, 353 | .apat = {6, 34, 62, 90, 118, 146, 0}, 354 | .ecc = { 355 | {.bs = 74, .dw = 46, .ns = 14}, 356 | {.bs = 145, .dw = 115, .ns = 13}, 357 | {.bs = 46, .dw = 16, .ns = 59}, 358 | {.bs = 54, .dw = 24, .ns = 44} 359 | } 360 | }, 361 | { /* Version 35 */ 362 | .data_bytes = 2876, 363 | .apat = {6, 30, 54, 78, 102, 126, 150}, 364 | .ecc = { 365 | {.bs = 75, .dw = 47, .ns = 12}, 366 | {.bs = 151, .dw = 121, .ns = 12}, 367 | {.bs = 45, .dw = 15, .ns = 22}, 368 | {.bs = 54, .dw = 24, .ns = 39} 369 | } 370 | }, 371 | { /* Version 36 */ 372 | .data_bytes = 3034, 373 | .apat = {6, 24, 50, 76, 102, 128, 154}, 374 | .ecc = { 375 | {.bs = 75, .dw = 47, .ns = 6}, 376 | {.bs = 151, .dw = 121, .ns = 6}, 377 | {.bs = 45, .dw = 15, .ns = 2}, 378 | {.bs = 54, .dw = 24, .ns = 46} 379 | } 380 | }, 381 | { /* Version 37 */ 382 | .data_bytes = 3196, 383 | .apat = {6, 28, 54, 80, 106, 132, 158}, 384 | .ecc = { 385 | {.bs = 74, .dw = 46, .ns = 29}, 386 | {.bs = 152, .dw = 122, .ns = 17}, 387 | {.bs = 45, .dw = 15, .ns = 24}, 388 | {.bs = 54, .dw = 24, .ns = 49} 389 | } 390 | }, 391 | { /* Version 38 */ 392 | .data_bytes = 3362, 393 | .apat = {6, 32, 58, 84, 110, 136, 162}, 394 | .ecc = { 395 | {.bs = 74, .dw = 46, .ns = 13}, 396 | {.bs = 152, .dw = 122, .ns = 4}, 397 | {.bs = 45, .dw = 15, .ns = 42}, 398 | {.bs = 54, .dw = 24, .ns = 48} 399 | } 400 | }, 401 | { /* Version 39 */ 402 | .data_bytes = 3532, 403 | .apat = {6, 26, 54, 82, 110, 138, 166}, 404 | .ecc = { 405 | {.bs = 75, .dw = 47, .ns = 40}, 406 | {.bs = 147, .dw = 117, .ns = 20}, 407 | {.bs = 45, .dw = 15, .ns = 10}, 408 | {.bs = 54, .dw = 24, .ns = 43} 409 | } 410 | }, 411 | { /* Version 40 */ 412 | .data_bytes = 3706, 413 | .apat = {6, 30, 58, 86, 114, 142, 170}, 414 | .ecc = { 415 | {.bs = 75, .dw = 47, .ns = 18}, 416 | {.bs = 148, .dw = 118, .ns = 19}, 417 | {.bs = 45, .dw = 15, .ns = 20}, 418 | {.bs = 54, .dw = 24, .ns = 34} 419 | } 420 | } 421 | }; 422 | -------------------------------------------------------------------------------- /test/data/generated/qrcodegen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QR Code generator library (C) 3 | * 4 | * Copyright (c) Project Nayuki. (MIT License) 5 | * https://www.nayuki.io/page/qr-code-generator-library 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * - The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * - The Software is provided "as is", without warranty of any kind, express or 16 | * implied, including but not limited to the warranties of merchantability, 17 | * fitness for a particular purpose and noninfringement. In no event shall the 18 | * authors or copyright holders be liable for any claim, damages or other 19 | * liability, whether in an action of contract, tort or otherwise, arising from, 20 | * out of or in connection with the Software or the use or other dealings in the 21 | * Software. 22 | */ 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | 36 | /* 37 | * This library creates QR Code symbols, which is a type of two-dimension barcode. 38 | * Invented by Denso Wave and described in the ISO/IEC 18004 standard. 39 | * A QR Code structure is an immutable square grid of black and white cells. 40 | * The library provides functions to create a QR Code from text or binary data. 41 | * The library covers the QR Code Model 2 specification, supporting all versions (sizes) 42 | * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. 43 | * 44 | * Ways to create a QR Code object: 45 | * - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary(). 46 | * - Low level: Custom-make the list of segments and call 47 | * qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced(). 48 | * (Note that all ways require supplying the desired error correction level and various byte buffers.) 49 | */ 50 | 51 | 52 | /*---- Enum and struct types----*/ 53 | 54 | /* 55 | * The error correction level in a QR Code symbol. 56 | */ 57 | enum qrcodegen_Ecc { 58 | // Must be declared in ascending order of error protection 59 | // so that an internal qrcodegen function works properly 60 | qrcodegen_Ecc_LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords 61 | qrcodegen_Ecc_MEDIUM , // The QR Code can tolerate about 15% erroneous codewords 62 | qrcodegen_Ecc_QUARTILE, // The QR Code can tolerate about 25% erroneous codewords 63 | qrcodegen_Ecc_HIGH , // The QR Code can tolerate about 30% erroneous codewords 64 | }; 65 | 66 | 67 | /* 68 | * The mask pattern used in a QR Code symbol. 69 | */ 70 | enum qrcodegen_Mask { 71 | // A special value to tell the QR Code encoder to 72 | // automatically select an appropriate mask pattern 73 | qrcodegen_Mask_AUTO = -1, 74 | // The eight actual mask patterns 75 | qrcodegen_Mask_0 = 0, 76 | qrcodegen_Mask_1, 77 | qrcodegen_Mask_2, 78 | qrcodegen_Mask_3, 79 | qrcodegen_Mask_4, 80 | qrcodegen_Mask_5, 81 | qrcodegen_Mask_6, 82 | qrcodegen_Mask_7, 83 | }; 84 | 85 | 86 | /* 87 | * Describes how a segment's data bits are interpreted. 88 | */ 89 | enum qrcodegen_Mode { 90 | qrcodegen_Mode_NUMERIC = 0x1, 91 | qrcodegen_Mode_ALPHANUMERIC = 0x2, 92 | qrcodegen_Mode_BYTE = 0x4, 93 | qrcodegen_Mode_KANJI = 0x8, 94 | qrcodegen_Mode_ECI = 0x7, 95 | }; 96 | 97 | 98 | /* 99 | * A segment of character/binary/control data in a QR Code symbol. 100 | * The mid-level way to create a segment is to take the payload data 101 | * and call a factory function such as qrcodegen_makeNumeric(). 102 | * The low-level way to create a segment is to custom-make the bit buffer 103 | * and initialize a qrcodegen_Segment struct with appropriate values. 104 | * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. 105 | * Any segment longer than this is meaningless for the purpose of generating QR Codes. 106 | * Moreover, the maximum allowed bit length is 32767 because 107 | * the largest QR Code (version 40) has 31329 modules. 108 | */ 109 | struct qrcodegen_Segment { 110 | // The mode indicator of this segment. 111 | enum qrcodegen_Mode mode; 112 | 113 | // The length of this segment's unencoded data. Measured in characters for 114 | // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. 115 | // Always zero or positive. Not the same as the data's bit length. 116 | int numChars; 117 | 118 | // The data bits of this segment, packed in bitwise big endian. 119 | // Can be null if the bit length is zero. 120 | uint8_t *data; 121 | 122 | // The number of valid data bits used in the buffer. Requires 123 | // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8. 124 | // The character count (numChars) must agree with the mode and the bit buffer length. 125 | int bitLength; 126 | }; 127 | 128 | 129 | 130 | /*---- Macro constants and functions ----*/ 131 | 132 | #define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard 133 | #define qrcodegen_VERSION_MAX 40 // The maximum version number supported in the QR Code Model 2 standard 134 | 135 | // Calculates the number of bytes needed to store any QR Code up to and including the given version number, 136 | // as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];' 137 | // can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16). 138 | // Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX. 139 | #define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1) 140 | 141 | // The worst-case number of bytes needed to store one QR Code, up to and including 142 | // version 40. This value equals 3918, which is just under 4 kilobytes. 143 | // Use this more convenient value to avoid calculating tighter memory bounds for buffers. 144 | #define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX) 145 | 146 | 147 | 148 | /*---- Functions (high level) to generate QR Codes ----*/ 149 | 150 | /* 151 | * Encodes the given text string to a QR Code, returning true if encoding succeeded. 152 | * If the data is too long to fit in any version in the given range 153 | * at the given ECC level, then false is returned. 154 | * - The input text must be encoded in UTF-8 and contain no NULs. 155 | * - The variables ecl and mask must correspond to enum constant values. 156 | * - Requires 1 <= minVersion <= maxVersion <= 40. 157 | * - The arrays tempBuffer and qrcode must each have a length 158 | * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion). 159 | * - After the function returns, tempBuffer contains no useful data. 160 | * - If successful, the resulting QR Code may use numeric, 161 | * alphanumeric, or byte mode to encode the text. 162 | * - In the most optimistic case, a QR Code at version 40 with low ECC 163 | * can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string 164 | * up to 4296 characters, or any digit string up to 7089 characters. 165 | * These numbers represent the hard upper limit of the QR Code standard. 166 | * - Please consult the QR Code specification for information on 167 | * data capacities per version, ECC level, and text encoding mode. 168 | */ 169 | bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], 170 | enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); 171 | 172 | 173 | /* 174 | * Encodes the given binary data to a QR Code, returning true if encoding succeeded. 175 | * If the data is too long to fit in any version in the given range 176 | * at the given ECC level, then false is returned. 177 | * - The input array range dataAndTemp[0 : dataLen] should normally be 178 | * valid UTF-8 text, but is not required by the QR Code standard. 179 | * - The variables ecl and mask must correspond to enum constant values. 180 | * - Requires 1 <= minVersion <= maxVersion <= 40. 181 | * - The arrays dataAndTemp and qrcode must each have a length 182 | * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion). 183 | * - After the function returns, the contents of dataAndTemp may have changed, 184 | * and does not represent useful data anymore. 185 | * - If successful, the resulting QR Code will use byte mode to encode the data. 186 | * - In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte 187 | * sequence up to length 2953. This is the hard upper limit of the QR Code standard. 188 | * - Please consult the QR Code specification for information on 189 | * data capacities per version, ECC level, and text encoding mode. 190 | */ 191 | bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], 192 | enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); 193 | 194 | 195 | /*---- Functions (low level) to generate QR Codes ----*/ 196 | 197 | /* 198 | * Renders a QR Code representing the given segments at the given error correction level. 199 | * The smallest possible QR Code version is automatically chosen for the output. Returns true if 200 | * QR Code creation succeeded, or false if the data is too long to fit in any version. The ECC level 201 | * of the result may be higher than the ecl argument if it can be done without increasing the version. 202 | * This function allows the user to create a custom sequence of segments that switches 203 | * between modes (such as alphanumeric and byte) to encode text in less space. 204 | * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). 205 | * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will 206 | * result in them being clobbered, but the QR Code output will still be correct. 207 | * But the qrcode array must not overlap tempBuffer or any segment's data buffer. 208 | */ 209 | bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, 210 | enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]); 211 | 212 | 213 | /* 214 | * Renders a QR Code representing the given segments with the given encoding parameters. 215 | * Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions. 216 | * The smallest possible QR Code version within the given range is automatically 217 | * chosen for the output. Iff boostEcl is true, then the ECC level of the result 218 | * may be higher than the ecl argument if it can be done without increasing the 219 | * version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or 220 | * qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow). 221 | * This function allows the user to create a custom sequence of segments that switches 222 | * between modes (such as alphanumeric and byte) to encode text in less space. 223 | * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). 224 | * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will 225 | * result in them being clobbered, but the QR Code output will still be correct. 226 | * But the qrcode array must not overlap tempBuffer or any segment's data buffer. 227 | */ 228 | bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, 229 | int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]); 230 | 231 | 232 | /* 233 | * Tests whether the given string can be encoded as a segment in alphanumeric mode. 234 | * A string is encodable iff each character is in the following set: 0 to 9, A to Z 235 | * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. 236 | */ 237 | bool qrcodegen_isAlphanumeric(const char *text); 238 | 239 | 240 | /* 241 | * Tests whether the given string can be encoded as a segment in numeric mode. 242 | * A string is encodable iff each character is in the range 0 to 9. 243 | */ 244 | bool qrcodegen_isNumeric(const char *text); 245 | 246 | 247 | /* 248 | * Returns the number of bytes (uint8_t) needed for the data buffer of a segment 249 | * containing the given number of characters using the given mode. Notes: 250 | * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or 251 | * the number of needed bits exceeds INT16_MAX (i.e. 32767). 252 | * - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096. 253 | * - It is okay for the user to allocate more bytes for the buffer than needed. 254 | * - For byte mode, numChars measures the number of bytes, not Unicode code points. 255 | * - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned. 256 | * An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. 257 | */ 258 | size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars); 259 | 260 | 261 | /* 262 | * Returns a segment representing the given binary data encoded in 263 | * byte mode. All input byte arrays are acceptable. Any text string 264 | * can be converted to UTF-8 bytes and encoded as a byte mode segment. 265 | */ 266 | struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]); 267 | 268 | 269 | /* 270 | * Returns a segment representing the given string of decimal digits encoded in numeric mode. 271 | */ 272 | struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]); 273 | 274 | 275 | /* 276 | * Returns a segment representing the given text string encoded in alphanumeric mode. 277 | * The characters allowed are: 0 to 9, A to Z (uppercase only), space, 278 | * dollar, percent, asterisk, plus, hyphen, period, slash, colon. 279 | */ 280 | struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]); 281 | 282 | 283 | /* 284 | * Returns a segment representing an Extended Channel Interpretation 285 | * (ECI) designator with the given assignment value. 286 | */ 287 | struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]); 288 | 289 | 290 | /*---- Functions to extract raw data from QR Codes ----*/ 291 | 292 | /* 293 | * Returns the side length of the given QR Code, assuming that encoding succeeded. 294 | * The result is in the range [21, 177]. Note that the length of the array buffer 295 | * is related to the side length - every 'uint8_t qrcode[]' must have length at least 296 | * qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1). 297 | */ 298 | int qrcodegen_getSize(const uint8_t qrcode[]); 299 | 300 | 301 | /* 302 | * Returns the color of the module (pixel) at the given coordinates, which is false 303 | * for white or true for black. The top left corner has the coordinates (x=0, y=0). 304 | * If the given coordinates are out of bounds, then false (white) is returned. 305 | */ 306 | bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y); 307 | 308 | 309 | #ifdef __cplusplus 310 | } 311 | #endif 312 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require("fs"); 4 | const path = require("path"); 5 | const util = require("util"); 6 | const jpeg = require("jpeg-js"); 7 | 8 | const chai = require("chai"); 9 | const expect = chai.expect; 10 | 11 | const quirc = require("../index.js"); 12 | 13 | // QR-code versions. 14 | const qr_versions = Array(40).fill(0).map((_, i) => i + 1); 15 | // QR-code ECC levels. 16 | const qr_ecc_levels = { 17 | ECC_LEVEL_M: "M", 18 | ECC_LEVEL_L: "L", 19 | ECC_LEVEL_H: "H", 20 | ECC_LEVEL_Q: "Q", 21 | }; 22 | // QR-code encoding modes. 23 | const qr_enc_modes = { 24 | MODE_NUMERIC: "NUMERIC", 25 | MODE_ALNUM: "ALNUM", 26 | MODE_BYTE: "BYTE", 27 | MODE_KANJI: "KANJI", 28 | }; 29 | 30 | const qr_eci = { 31 | ECI_ISO_8859_1: "ISO_8859_1", 32 | ECI_IBM437: "IBM437", 33 | ECI_ISO_8859_2: "ISO_8859_2", 34 | ECI_ISO_8859_3: "ISO_8859_3", 35 | ECI_ISO_8859_4: "ISO_8859_4", 36 | ECI_ISO_8859_5: "ISO_8859_5", 37 | ECI_ISO_8859_6: "ISO_8859_6", 38 | ECI_ISO_8859_7: "ISO_8859_7", 39 | ECI_ISO_8859_8: "ISO_8859_8", 40 | ECI_ISO_8859_9: "ISO_8859_9", 41 | ECI_WINDOWS_874: "WINDOWS_874", 42 | ECI_ISO_8859_13: "ISO_8859_13", 43 | ECI_ISO_8859_15: "ISO_8859_15", 44 | ECI_SHIFT_JIS: "SHIFT_JIS", 45 | ECI_UTF_8: "UTF_8", 46 | }; 47 | 48 | const extensions = ["png", "jpeg"]; 49 | 50 | /* helpers for test data files */ 51 | function test_data_path(local_path) { 52 | return path.join(__dirname, "data", local_path); 53 | } 54 | 55 | function read_test_data(local_path) { 56 | return fs.readFileSync(test_data_path(local_path)); 57 | } 58 | 59 | describe("constants", function () { 60 | describe("QR-code versions", function () { 61 | it("should set VERSION_MIN to 1", function () { 62 | expect(quirc.constants.VERSION_MIN).to.exist.and.to.eql(1); 63 | }); 64 | it("should set VERSION_MAX to 40", function () { 65 | expect(quirc.constants.VERSION_MAX).to.exist.and.to.eql(40); 66 | }); 67 | }); 68 | 69 | describe("QR-code ECC levels", function () { 70 | for (const [key, value] of Object.entries(qr_ecc_levels)) { 71 | it(`should set ${key} to ${value}`, function () { 72 | expect(quirc.constants[key]).to.exist.and.to.eql(value); 73 | }); 74 | } 75 | }); 76 | 77 | describe("QR-code encoding modes", function () { 78 | for (const [key, value] of Object.entries(qr_enc_modes)) { 79 | it(`should set ${key} to ${value}`, function () { 80 | expect(quirc.constants[key]).to.exist.and.to.eql(value); 81 | }); 82 | } 83 | }); 84 | 85 | describe("QR-code ECI", function () { 86 | for (const [key, value] of Object.entries(qr_eci)) { 87 | it(`should set ${key} to ${value}`, function () { 88 | expect(quirc.constants[key]).to.exist.and.to.eql(value); 89 | }); 90 | } 91 | }); 92 | }); 93 | 94 | describe("decode()", function () { 95 | describe("arguments", function () { 96 | it("should return a rejected Promise when no arguments are given", function (done) { 97 | const p = quirc.decode() 98 | expect(p).to.be.a("Promise"); 99 | p.catch((e) => { 100 | expect(e.message).to.eql("img must be a Buffer or ImageData"); 101 | done(); 102 | }); 103 | }); 104 | it("should return a Promise when only one argument is given", function () { 105 | const p = quirc.decode(Buffer.from("data")); 106 | expect(p).to.be.a("Promise"); 107 | p.catch((e) => { /* ignored */ }); 108 | }); 109 | it("should throw when img is not a Buffer", function () { 110 | expect(function () { 111 | quirc.decode("a string", function dummy() { }); 112 | }).to.throw(TypeError, "img must be a Buffer or ImageData"); 113 | }); 114 | it("should throw when callback is not a function", function () { 115 | expect(function () { 116 | quirc.decode(Buffer.from(""), "not a function"); 117 | }).to.throw(TypeError, "callback must be a function"); 118 | }); 119 | }); 120 | 121 | context("when the buffer data is empty", function () { 122 | it("should yield an Error", function (done) { 123 | quirc.decode(Buffer.from(""), function (err, codes) { 124 | expect(err).to.exist.and.to.be.an("error"); 125 | expect(err.message).to.eql("failed to load image"); 126 | return done(); 127 | }); 128 | }); 129 | }); 130 | 131 | context("when the buffer data is not an image", function () { 132 | it("should yield an Error", function (done) { 133 | quirc.decode(Buffer.from("Hello World"), function (err, codes) { 134 | expect(err).to.exist.and.to.be.an("error"); 135 | expect(err.message).to.eql("failed to load image"); 136 | return done(); 137 | }); 138 | }); 139 | }); 140 | 141 | extensions.forEach(function (ext) { 142 | context(`${ext}`, function () { 143 | context("when the image file has no QR Code", function () { 144 | let empty_image; 145 | before(function () { 146 | empty_image = read_test_data(`1x1.${ext}`); 147 | }); 148 | 149 | it("should not yield an Error", function (done) { 150 | quirc.decode(empty_image, function (err, codes) { 151 | expect(err).to.not.exist; 152 | return done(); 153 | }); 154 | }); 155 | it("should not yield a result", function (done) { 156 | quirc.decode(empty_image, function (err, codes) { 157 | expect(codes).to.be.an('array').and.to.have.length(0); 158 | return done(); 159 | }); 160 | }); 161 | }); 162 | 163 | context("when the image file has multiple QR Code", function () { 164 | let hello_plus_world; 165 | before(function () { 166 | hello_plus_world = read_test_data(`Hello+World.${ext}`); 167 | }); 168 | 169 | it("should not yield an Error", function (done) { 170 | quirc.decode(hello_plus_world, function (err, codes) { 171 | expect(err).to.not.exist; 172 | return done(); 173 | }); 174 | }); 175 | it("should yield two results", function (done) { 176 | quirc.decode(hello_plus_world, function (err, codes) { 177 | expect(codes).to.be.an('array').and.to.have.length(2); 178 | return done(); 179 | }); 180 | }); 181 | it("should yield the first QR Code", function (done) { 182 | quirc.decode(hello_plus_world, function (err, codes) { 183 | expect(codes[0].err).to.not.exist; 184 | expect(codes[0].version).to.eql(1); 185 | expect(codes[0].ecc_level).to.eql("H"); 186 | expect(codes[0].mask).to.eql(1); 187 | expect(codes[0].mode).to.eql("BYTE"); 188 | expect(codes[1].eci).to.eql("UTF_8"); 189 | expect(codes[0].data).to.be.an.instanceof(Buffer); 190 | expect(codes[0].data.toString()).to.eql("Hello"); 191 | return done(); 192 | }); 193 | }); 194 | it("should yield the second QR Code", function (done) { 195 | quirc.decode(hello_plus_world, function (err, codes) { 196 | expect(codes[1].err).to.not.exist; 197 | expect(codes[1].version).to.eql(1); 198 | expect(codes[1].ecc_level).to.eql("H"); 199 | expect(codes[1].mask).to.eql(3); 200 | expect(codes[1].mode).to.eql("BYTE"); 201 | expect(codes[1].eci).to.eql("UTF_8"); 202 | expect(codes[1].data).to.be.an.instanceof(Buffer); 203 | expect(codes[1].data.toString()).to.eql("World"); 204 | return done(); 205 | }); 206 | }); 207 | }); 208 | 209 | context("when the QR code is flipped", function () { 210 | let image_with_flipped_qr_code; 211 | before(function () { 212 | image_with_flipped_qr_code = read_test_data(`flipped.${ext}`); 213 | }); 214 | 215 | it("should not yield an Error", function (done) { 216 | quirc.decode(image_with_flipped_qr_code, function (err, codes) { 217 | expect(err).to.not.exist; 218 | return done(); 219 | }); 220 | }); 221 | it("should yield two results", function (done) { 222 | quirc.decode(image_with_flipped_qr_code, function (err, codes) { 223 | expect(codes).to.be.an('array').and.to.have.length(2); 224 | return done(); 225 | }); 226 | }); 227 | it("should yield the first QR Code", function (done) { 228 | quirc.decode(image_with_flipped_qr_code, function (err, codes) { 229 | expect(codes[0].err).to.not.exist; 230 | expect(codes[0].version).to.eql(3); 231 | expect(codes[0].ecc_level).to.eql("L"); 232 | expect(codes[0].mask).to.eql(3); 233 | expect(codes[0].mode).to.eql("BYTE"); 234 | expect(codes[0].eci).to.eql("UTF_8"); 235 | expect(codes[0].data).to.be.an.instanceof(Buffer); 236 | expect(codes[0].data.toString()).to.eql("The quick brown fox jumps over the lazy dog"); 237 | return done(); 238 | }); 239 | }); 240 | it("should yield the second QR Code", function (done) { 241 | quirc.decode(image_with_flipped_qr_code, function (err, codes) { 242 | expect(codes[1].err).to.not.exist; 243 | expect(codes[1].version).to.eql(3); 244 | expect(codes[1].ecc_level).to.eql("L"); 245 | expect(codes[1].mask).to.eql(3); 246 | expect(codes[1].mode).to.eql("BYTE"); 247 | expect(codes[1].eci).to.eql("UTF_8"); 248 | expect(codes[1].data).to.be.an.instanceof(Buffer); 249 | expect(codes[1].data.toString()).to.eql("The quick brown fox jumps over the lazy dog"); 250 | return done(); 251 | }); 252 | }); 253 | }); 254 | 255 | /* 256 | * This context() ensure that quirc was compiled with QUIRC_MAX_REGIONS > 256. 257 | * 258 | * see https://github.com/dlbeer/quirc/issues/2 for the test image file and 259 | * https://github.com/dlbeer/quirc/pull/9 for the rational. 260 | */ 261 | context("when the image file is big", function () { 262 | let big_image_with_two_qrcodes; 263 | before(function () { 264 | big_image_with_two_qrcodes = read_test_data(`big_image_with_two_qrcodes.${ext}`); 265 | }); 266 | 267 | it("should not yield an Error", function (done) { 268 | quirc.decode(big_image_with_two_qrcodes, function (err, codes) { 269 | expect(err).to.not.exist; 270 | return done(); 271 | }); 272 | }); 273 | it("should yield two results", function (done) { 274 | quirc.decode(big_image_with_two_qrcodes, function (err, codes) { 275 | expect(codes).to.be.an('array').and.to.have.length(2); 276 | return done(); 277 | }); 278 | }); 279 | it("should yield the first QR Code", function (done) { 280 | quirc.decode(big_image_with_two_qrcodes, function (err, codes) { 281 | expect(codes[0].err).to.not.exist; 282 | expect(codes[0].version).to.eql(4); 283 | expect(codes[0].ecc_level).to.eql("M"); 284 | expect(codes[0].mask).to.eql(2); 285 | expect(codes[0].mode).to.eql("BYTE"); 286 | expect(codes[0].data).to.be.an.instanceof(Buffer); 287 | expect(codes[0].data.toString()).to.eql("from javascript"); 288 | return done(); 289 | }); 290 | }); 291 | it("should yield the second QR Code", function (done) { 292 | quirc.decode(big_image_with_two_qrcodes, function (err, codes) { 293 | expect(codes[1].err).to.not.exist; 294 | expect(codes[1].version).to.eql(4); 295 | expect(codes[1].ecc_level).to.eql("M"); 296 | expect(codes[1].mask).to.eql(2); 297 | expect(codes[1].mode).to.eql("BYTE"); 298 | expect(codes[1].data).to.be.an.instanceof(Buffer); 299 | expect(codes[1].data.toString()).to.eql("here comes qr!"); 300 | return done(); 301 | }); 302 | }); 303 | }); 304 | }); 305 | }); 306 | 307 | context("using generated file", function () { 308 | const mode_to_data = { 309 | NUMERIC: "42", 310 | ALNUM: "AC-42", 311 | BYTE: "aA1234", 312 | KANJI: [0x93, 0x5f, 0xe4, 0xaa], // 点茗 in Shift-JIS 313 | }; 314 | 315 | function test_filename(version, ecc_level, mode) { 316 | const fmt = "version=%s,level=%s,mode=%s.png"; 317 | // pad version with a leading 0 if needed to "simulate" printf's 318 | // %02d format. 319 | const version_str = ("0" + version).slice(-2); 320 | return util.format(fmt, version_str, ecc_level, mode); 321 | } 322 | 323 | for (const version of qr_versions) { 324 | for (const [_, ecc_level] of Object.entries(qr_ecc_levels)) { 325 | for (const [_, mode] of Object.entries(qr_enc_modes)) { 326 | const fname = test_filename(version, ecc_level, mode); 327 | context(fname, function () { 328 | // relative path for test_data_path() and 329 | // read_test_data() 330 | const rpath = "generated/" + fname; 331 | // use accessSync(), because async it() calls 332 | // won't register as expected. 333 | let found = false; 334 | try { 335 | // XXX: TOCTOU but meh 336 | fs.accessSync(test_data_path(rpath), fs.constants.R_OK); 337 | found = true; 338 | } catch (e) { 339 | found = false; 340 | } 341 | if (!found) { 342 | it.skip(rpath + " not found, skipped"); 343 | } else { 344 | it("should yield the QR Code", function (done) { 345 | var image = read_test_data(rpath); 346 | quirc.decode(image, function (err, codes) { 347 | expect(err).to.not.exist; 348 | expect(codes).to.be.an('array').and.to.have.length(1); 349 | expect(codes[0].version).to.eql(version); 350 | expect(codes[0].ecc_level).to.eql(ecc_level); 351 | expect(codes[0].mode).to.eql(mode); 352 | expect(codes[0].data).to.be.an.instanceof(Buffer); 353 | expect(codes[0].data).to.eql(Buffer.from(mode_to_data[mode])); 354 | return done(); 355 | }); 356 | }); 357 | } 358 | }); 359 | } 360 | } 361 | } 362 | }); 363 | 364 | context("raw image data", function () { 365 | it("should read QR codes from raw image data", function (done) { 366 | const big_image_with_two_qrcodes = jpeg.decode( 367 | read_test_data("big_image_with_two_qrcodes.jpeg") 368 | ); 369 | quirc.decode(big_image_with_two_qrcodes, function (err, codes) { 370 | expect(codes).to.be.an("array").and.to.have.length(2); 371 | expect(codes[0].err).to.not.exist; 372 | expect(codes[0].version).to.eql(4); 373 | expect(codes[0].ecc_level).to.eql("M"); 374 | expect(codes[0].mask).to.eql(2); 375 | expect(codes[0].mode).to.eql("BYTE"); 376 | expect(codes[0].data).to.be.an.instanceof(Buffer); 377 | expect(codes[0].data.toString()).to.eql("from javascript"); 378 | expect(codes[1].err).to.not.exist; 379 | expect(codes[1].version).to.eql(4); 380 | expect(codes[1].ecc_level).to.eql("M"); 381 | expect(codes[1].mask).to.eql(2); 382 | expect(codes[1].mode).to.eql("BYTE"); 383 | expect(codes[1].data).to.be.an.instanceof(Buffer); 384 | expect(codes[1].data.toString()).to.eql("here comes qr!"); 385 | done(); 386 | }); 387 | }); 388 | }); 389 | 390 | context("regressions", function () { 391 | // https://github.com/dlbeer/quirc/pull/87 392 | context("dark image", function () { 393 | let img; 394 | before(function () { 395 | img = read_test_data("black.png") 396 | }); 397 | 398 | it("should not yield an Error", function (done) { 399 | quirc.decode(img, function (err, codes) { 400 | expect(err).to.not.exist; 401 | return done(); 402 | }); 403 | }); 404 | it("should not yield a result", function (done) { 405 | quirc.decode(img, function (err, codes) { 406 | expect(codes).to.be.an('array').and.to.have.length(0); 407 | return done(); 408 | }); 409 | }); 410 | }); 411 | }); 412 | }); 413 | -------------------------------------------------------------------------------- /deps/quirc/decode.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "quirc_internal.h" 18 | 19 | #include 20 | #include 21 | 22 | #define MAX_POLY 64 23 | 24 | /************************************************************************ 25 | * Galois fields 26 | */ 27 | 28 | struct galois_field { 29 | int p; 30 | const uint8_t *log; 31 | const uint8_t *exp; 32 | }; 33 | 34 | static const uint8_t gf16_exp[16] = { 35 | 0x01, 0x02, 0x04, 0x08, 0x03, 0x06, 0x0c, 0x0b, 36 | 0x05, 0x0a, 0x07, 0x0e, 0x0f, 0x0d, 0x09, 0x01 37 | }; 38 | 39 | static const uint8_t gf16_log[16] = { 40 | 0x00, 0x0f, 0x01, 0x04, 0x02, 0x08, 0x05, 0x0a, 41 | 0x03, 0x0e, 0x09, 0x07, 0x06, 0x0d, 0x0b, 0x0c 42 | }; 43 | 44 | static const struct galois_field gf16 = { 45 | .p = 15, 46 | .log = gf16_log, 47 | .exp = gf16_exp 48 | }; 49 | 50 | static const uint8_t gf256_exp[256] = { 51 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 52 | 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 53 | 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 54 | 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 55 | 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 56 | 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 57 | 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 58 | 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 59 | 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 60 | 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 61 | 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 62 | 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, 63 | 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 64 | 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 65 | 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 66 | 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 67 | 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 68 | 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, 69 | 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 70 | 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 71 | 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 72 | 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 73 | 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 74 | 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, 75 | 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 76 | 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 77 | 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 78 | 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, 79 | 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 80 | 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, 81 | 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 82 | 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01 83 | }; 84 | 85 | static const uint8_t gf256_log[256] = { 86 | 0x00, 0xff, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 87 | 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 88 | 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 89 | 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, 90 | 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 91 | 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 92 | 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 93 | 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 94 | 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 95 | 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 96 | 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 97 | 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, 98 | 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 99 | 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, 100 | 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 101 | 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 102 | 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 103 | 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, 104 | 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 105 | 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 106 | 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 107 | 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 108 | 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 109 | 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, 110 | 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 111 | 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, 112 | 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 113 | 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 114 | 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 115 | 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, 116 | 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 117 | 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf 118 | }; 119 | 120 | static const struct galois_field gf256 = { 121 | .p = 255, 122 | .log = gf256_log, 123 | .exp = gf256_exp 124 | }; 125 | 126 | /************************************************************************ 127 | * Polynomial operations 128 | */ 129 | 130 | static void poly_add(uint8_t *dst, const uint8_t *src, uint8_t c, 131 | int shift, const struct galois_field *gf) 132 | { 133 | int i; 134 | int log_c = gf->log[c]; 135 | 136 | if (!c) 137 | return; 138 | 139 | for (i = 0; i < MAX_POLY; i++) { 140 | int p = i + shift; 141 | uint8_t v = src[i]; 142 | 143 | if (p < 0 || p >= MAX_POLY) 144 | continue; 145 | if (!v) 146 | continue; 147 | 148 | dst[p] ^= gf->exp[(gf->log[v] + log_c) % gf->p]; 149 | } 150 | } 151 | 152 | static uint8_t poly_eval(const uint8_t *s, uint8_t x, 153 | const struct galois_field *gf) 154 | { 155 | int i; 156 | uint8_t sum = 0; 157 | uint8_t log_x = gf->log[x]; 158 | 159 | if (!x) 160 | return s[0]; 161 | 162 | for (i = 0; i < MAX_POLY; i++) { 163 | uint8_t c = s[i]; 164 | 165 | if (!c) 166 | continue; 167 | 168 | sum ^= gf->exp[(gf->log[c] + log_x * i) % gf->p]; 169 | } 170 | 171 | return sum; 172 | } 173 | 174 | /************************************************************************ 175 | * Berlekamp-Massey algorithm for finding error locator polynomials. 176 | */ 177 | 178 | static void berlekamp_massey(const uint8_t *s, int N, 179 | const struct galois_field *gf, 180 | uint8_t *sigma) 181 | { 182 | uint8_t C[MAX_POLY]; 183 | uint8_t B[MAX_POLY]; 184 | int L = 0; 185 | int m = 1; 186 | uint8_t b = 1; 187 | int n; 188 | 189 | memset(B, 0, sizeof(B)); 190 | memset(C, 0, sizeof(C)); 191 | B[0] = 1; 192 | C[0] = 1; 193 | 194 | for (n = 0; n < N; n++) { 195 | uint8_t d = s[n]; 196 | uint8_t mult; 197 | int i; 198 | 199 | for (i = 1; i <= L; i++) { 200 | if (!(C[i] && s[n - i])) 201 | continue; 202 | 203 | d ^= gf->exp[(gf->log[C[i]] + 204 | gf->log[s[n - i]]) % 205 | gf->p]; 206 | } 207 | 208 | mult = gf->exp[(gf->p - gf->log[b] + gf->log[d]) % gf->p]; 209 | 210 | if (!d) { 211 | m++; 212 | } else if (L * 2 <= n) { 213 | uint8_t T[MAX_POLY]; 214 | 215 | memcpy(T, C, sizeof(T)); 216 | poly_add(C, B, mult, m, gf); 217 | memcpy(B, T, sizeof(B)); 218 | L = n + 1 - L; 219 | b = d; 220 | m = 1; 221 | } else { 222 | poly_add(C, B, mult, m, gf); 223 | m++; 224 | } 225 | } 226 | 227 | memcpy(sigma, C, MAX_POLY); 228 | } 229 | 230 | /************************************************************************ 231 | * Code stream error correction 232 | * 233 | * Generator polynomial for GF(2^8) is x^8 + x^4 + x^3 + x^2 + 1 234 | */ 235 | 236 | static int block_syndromes(const uint8_t *data, int bs, int npar, uint8_t *s) 237 | { 238 | int nonzero = 0; 239 | int i; 240 | 241 | memset(s, 0, MAX_POLY); 242 | 243 | for (i = 0; i < npar; i++) { 244 | int j; 245 | 246 | for (j = 0; j < bs; j++) { 247 | uint8_t c = data[bs - j - 1]; 248 | 249 | if (!c) 250 | continue; 251 | 252 | s[i] ^= gf256_exp[((int)gf256_log[c] + 253 | i * j) % 255]; 254 | } 255 | 256 | if (s[i]) 257 | nonzero = 1; 258 | } 259 | 260 | return nonzero; 261 | } 262 | 263 | static void eloc_poly(uint8_t *omega, 264 | const uint8_t *s, const uint8_t *sigma, 265 | int npar) 266 | { 267 | int i; 268 | 269 | memset(omega, 0, MAX_POLY); 270 | 271 | for (i = 0; i < npar; i++) { 272 | const uint8_t a = sigma[i]; 273 | const uint8_t log_a = gf256_log[a]; 274 | int j; 275 | 276 | if (!a) 277 | continue; 278 | 279 | for (j = 0; j + 1 < MAX_POLY; j++) { 280 | const uint8_t b = s[j + 1]; 281 | 282 | if (i + j >= npar) 283 | break; 284 | 285 | if (!b) 286 | continue; 287 | 288 | omega[i + j] ^= 289 | gf256_exp[(log_a + gf256_log[b]) % 255]; 290 | } 291 | } 292 | } 293 | 294 | static quirc_decode_error_t correct_block(uint8_t *data, 295 | const struct quirc_rs_params *ecc) 296 | { 297 | int npar = ecc->bs - ecc->dw; 298 | uint8_t s[MAX_POLY]; 299 | uint8_t sigma[MAX_POLY]; 300 | uint8_t sigma_deriv[MAX_POLY]; 301 | uint8_t omega[MAX_POLY]; 302 | int i; 303 | 304 | /* Compute syndrome vector */ 305 | if (!block_syndromes(data, ecc->bs, npar, s)) 306 | return QUIRC_SUCCESS; 307 | 308 | berlekamp_massey(s, npar, &gf256, sigma); 309 | 310 | /* Compute derivative of sigma */ 311 | memset(sigma_deriv, 0, MAX_POLY); 312 | for (i = 0; i + 1 < MAX_POLY; i += 2) 313 | sigma_deriv[i] = sigma[i + 1]; 314 | 315 | /* Compute error evaluator polynomial */ 316 | eloc_poly(omega, s, sigma, npar - 1); 317 | 318 | /* Find error locations and magnitudes */ 319 | for (i = 0; i < ecc->bs; i++) { 320 | uint8_t xinv = gf256_exp[255 - i]; 321 | 322 | if (!poly_eval(sigma, xinv, &gf256)) { 323 | uint8_t sd_x = poly_eval(sigma_deriv, xinv, &gf256); 324 | uint8_t omega_x = poly_eval(omega, xinv, &gf256); 325 | uint8_t error = gf256_exp[(255 - gf256_log[sd_x] + 326 | gf256_log[omega_x]) % 255]; 327 | 328 | data[ecc->bs - i - 1] ^= error; 329 | } 330 | } 331 | 332 | if (block_syndromes(data, ecc->bs, npar, s)) 333 | return QUIRC_ERROR_DATA_ECC; 334 | 335 | return QUIRC_SUCCESS; 336 | } 337 | 338 | /************************************************************************ 339 | * Format value error correction 340 | * 341 | * Generator polynomial for GF(2^4) is x^4 + x + 1 342 | */ 343 | 344 | #define FORMAT_MAX_ERROR 3 345 | #define FORMAT_SYNDROMES (FORMAT_MAX_ERROR * 2) 346 | #define FORMAT_BITS 15 347 | 348 | static int format_syndromes(uint16_t u, uint8_t *s) 349 | { 350 | int i; 351 | int nonzero = 0; 352 | 353 | memset(s, 0, MAX_POLY); 354 | 355 | for (i = 0; i < FORMAT_SYNDROMES; i++) { 356 | int j; 357 | 358 | s[i] = 0; 359 | for (j = 0; j < FORMAT_BITS; j++) 360 | if (u & (1 << j)) 361 | s[i] ^= gf16_exp[((i + 1) * j) % 15]; 362 | 363 | if (s[i]) 364 | nonzero = 1; 365 | } 366 | 367 | return nonzero; 368 | } 369 | 370 | static quirc_decode_error_t correct_format(uint16_t *f_ret) 371 | { 372 | uint16_t u = *f_ret; 373 | int i; 374 | uint8_t s[MAX_POLY]; 375 | uint8_t sigma[MAX_POLY]; 376 | 377 | /* Evaluate U (received codeword) at each of alpha_1 .. alpha_6 378 | * to get S_1 .. S_6 (but we index them from 0). 379 | */ 380 | if (!format_syndromes(u, s)) 381 | return QUIRC_SUCCESS; 382 | 383 | berlekamp_massey(s, FORMAT_SYNDROMES, &gf16, sigma); 384 | 385 | /* Now, find the roots of the polynomial */ 386 | for (i = 0; i < 15; i++) 387 | if (!poly_eval(sigma, gf16_exp[15 - i], &gf16)) 388 | u ^= (1 << i); 389 | 390 | if (format_syndromes(u, s)) 391 | return QUIRC_ERROR_FORMAT_ECC; 392 | 393 | *f_ret = u; 394 | return QUIRC_SUCCESS; 395 | } 396 | 397 | /************************************************************************ 398 | * Decoder algorithm 399 | */ 400 | 401 | struct datastream { 402 | uint8_t raw[QUIRC_MAX_PAYLOAD]; 403 | int data_bits; 404 | int ptr; 405 | 406 | uint8_t data[QUIRC_MAX_PAYLOAD]; 407 | }; 408 | 409 | static inline int grid_bit(const struct quirc_code *code, int x, int y) 410 | { 411 | int p = y * code->size + x; 412 | return (code->cell_bitmap[p >> 3] >> (p & 7)) & 1; 413 | } 414 | 415 | static quirc_decode_error_t read_format(const struct quirc_code *code, 416 | struct quirc_data *data, int which) 417 | { 418 | int i; 419 | uint16_t format = 0; 420 | uint16_t fdata; 421 | quirc_decode_error_t err; 422 | 423 | if (which) { 424 | for (i = 0; i < 7; i++) 425 | format = (format << 1) | 426 | grid_bit(code, 8, code->size - 1 - i); 427 | for (i = 0; i < 8; i++) 428 | format = (format << 1) | 429 | grid_bit(code, code->size - 8 + i, 8); 430 | } else { 431 | static const int xs[15] = { 432 | 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 4, 3, 2, 1, 0 433 | }; 434 | static const int ys[15] = { 435 | 0, 1, 2, 3, 4, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8 436 | }; 437 | 438 | for (i = 14; i >= 0; i--) 439 | format = (format << 1) | grid_bit(code, xs[i], ys[i]); 440 | } 441 | 442 | format ^= 0x5412; 443 | 444 | err = correct_format(&format); 445 | if (err) 446 | return err; 447 | 448 | fdata = format >> 10; 449 | data->ecc_level = fdata >> 3; 450 | data->mask = fdata & 7; 451 | 452 | return QUIRC_SUCCESS; 453 | } 454 | 455 | static int mask_bit(int mask, int i, int j) 456 | { 457 | switch (mask) { 458 | case 0: return !((i + j) % 2); 459 | case 1: return !(i % 2); 460 | case 2: return !(j % 3); 461 | case 3: return !((i + j) % 3); 462 | case 4: return !(((i / 2) + (j / 3)) % 2); 463 | case 5: return !((i * j) % 2 + (i * j) % 3); 464 | case 6: return !(((i * j) % 2 + (i * j) % 3) % 2); 465 | case 7: return !(((i * j) % 3 + (i + j) % 2) % 2); 466 | } 467 | 468 | return 0; 469 | } 470 | 471 | static int reserved_cell(int version, int i, int j) 472 | { 473 | const struct quirc_version_info *ver = &quirc_version_db[version]; 474 | int size = version * 4 + 17; 475 | int ai = -1, aj = -1, a; 476 | 477 | /* Finder + format: top left */ 478 | if (i < 9 && j < 9) 479 | return 1; 480 | 481 | /* Finder + format: bottom left */ 482 | if (i + 8 >= size && j < 9) 483 | return 1; 484 | 485 | /* Finder + format: top right */ 486 | if (i < 9 && j + 8 >= size) 487 | return 1; 488 | 489 | /* Exclude timing patterns */ 490 | if (i == 6 || j == 6) 491 | return 1; 492 | 493 | /* Exclude version info, if it exists. Version info sits adjacent to 494 | * the top-right and bottom-left finders in three rows, bounded by 495 | * the timing pattern. 496 | */ 497 | if (version >= 7) { 498 | if (i < 6 && j + 11 >= size) 499 | return 1; 500 | if (i + 11 >= size && j < 6) 501 | return 1; 502 | } 503 | 504 | /* Exclude alignment patterns */ 505 | for (a = 0; a < QUIRC_MAX_ALIGNMENT && ver->apat[a]; a++) { 506 | int p = ver->apat[a]; 507 | 508 | if (abs(p - i) < 3) 509 | ai = a; 510 | if (abs(p - j) < 3) 511 | aj = a; 512 | } 513 | 514 | if (ai >= 0 && aj >= 0) { 515 | a--; 516 | if (ai > 0 && ai < a) 517 | return 1; 518 | if (aj > 0 && aj < a) 519 | return 1; 520 | if (aj == a && ai == a) 521 | return 1; 522 | } 523 | 524 | return 0; 525 | } 526 | 527 | static void read_bit(const struct quirc_code *code, 528 | struct quirc_data *data, 529 | struct datastream *ds, int i, int j) 530 | { 531 | int bitpos = ds->data_bits & 7; 532 | int bytepos = ds->data_bits >> 3; 533 | int v = grid_bit(code, j, i); 534 | 535 | if (mask_bit(data->mask, i, j)) 536 | v ^= 1; 537 | 538 | if (v) 539 | ds->raw[bytepos] |= (0x80 >> bitpos); 540 | 541 | ds->data_bits++; 542 | } 543 | 544 | static void read_data(const struct quirc_code *code, 545 | struct quirc_data *data, 546 | struct datastream *ds) 547 | { 548 | int y = code->size - 1; 549 | int x = code->size - 1; 550 | int dir = -1; 551 | 552 | while (x > 0) { 553 | if (x == 6) 554 | x--; 555 | 556 | if (!reserved_cell(data->version, y, x)) 557 | read_bit(code, data, ds, y, x); 558 | 559 | if (!reserved_cell(data->version, y, x - 1)) 560 | read_bit(code, data, ds, y, x - 1); 561 | 562 | y += dir; 563 | if (y < 0 || y >= code->size) { 564 | dir = -dir; 565 | x -= 2; 566 | y += dir; 567 | } 568 | } 569 | } 570 | 571 | static quirc_decode_error_t codestream_ecc(struct quirc_data *data, 572 | struct datastream *ds) 573 | { 574 | const struct quirc_version_info *ver = 575 | &quirc_version_db[data->version]; 576 | const struct quirc_rs_params *sb_ecc = &ver->ecc[data->ecc_level]; 577 | struct quirc_rs_params lb_ecc; 578 | const int lb_count = 579 | (ver->data_bytes - sb_ecc->bs * sb_ecc->ns) / (sb_ecc->bs + 1); 580 | const int bc = lb_count + sb_ecc->ns; 581 | const int ecc_offset = sb_ecc->dw * bc + lb_count; 582 | int dst_offset = 0; 583 | int i; 584 | 585 | memcpy(&lb_ecc, sb_ecc, sizeof(lb_ecc)); 586 | lb_ecc.dw++; 587 | lb_ecc.bs++; 588 | 589 | for (i = 0; i < bc; i++) { 590 | uint8_t *dst = ds->data + dst_offset; 591 | const struct quirc_rs_params *ecc = 592 | (i < sb_ecc->ns) ? sb_ecc : &lb_ecc; 593 | const int num_ec = ecc->bs - ecc->dw; 594 | quirc_decode_error_t err; 595 | int j; 596 | 597 | for (j = 0; j < ecc->dw; j++) 598 | dst[j] = ds->raw[j * bc + i]; 599 | for (j = 0; j < num_ec; j++) 600 | dst[ecc->dw + j] = ds->raw[ecc_offset + j * bc + i]; 601 | 602 | err = correct_block(dst, ecc); 603 | if (err) 604 | return err; 605 | 606 | dst_offset += ecc->dw; 607 | } 608 | 609 | ds->data_bits = dst_offset * 8; 610 | 611 | return QUIRC_SUCCESS; 612 | } 613 | 614 | static inline int bits_remaining(const struct datastream *ds) 615 | { 616 | return ds->data_bits - ds->ptr; 617 | } 618 | 619 | static int take_bits(struct datastream *ds, int len) 620 | { 621 | int ret = 0; 622 | 623 | while (len && (ds->ptr < ds->data_bits)) { 624 | uint8_t b = ds->data[ds->ptr >> 3]; 625 | int bitpos = ds->ptr & 7; 626 | 627 | ret <<= 1; 628 | if ((b << bitpos) & 0x80) 629 | ret |= 1; 630 | 631 | ds->ptr++; 632 | len--; 633 | } 634 | 635 | return ret; 636 | } 637 | 638 | static int numeric_tuple(struct quirc_data *data, 639 | struct datastream *ds, 640 | int bits, int digits) 641 | { 642 | int tuple; 643 | int i; 644 | 645 | if (bits_remaining(ds) < bits) 646 | return -1; 647 | 648 | tuple = take_bits(ds, bits); 649 | 650 | for (i = digits - 1; i >= 0; i--) { 651 | data->payload[data->payload_len + i] = tuple % 10 + '0'; 652 | tuple /= 10; 653 | } 654 | 655 | data->payload_len += digits; 656 | return 0; 657 | } 658 | 659 | static quirc_decode_error_t decode_numeric(struct quirc_data *data, 660 | struct datastream *ds) 661 | { 662 | int bits = 14; 663 | int count; 664 | 665 | if (data->version < 10) 666 | bits = 10; 667 | else if (data->version < 27) 668 | bits = 12; 669 | 670 | count = take_bits(ds, bits); 671 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 672 | return QUIRC_ERROR_DATA_OVERFLOW; 673 | 674 | while (count >= 3) { 675 | if (numeric_tuple(data, ds, 10, 3) < 0) 676 | return QUIRC_ERROR_DATA_UNDERFLOW; 677 | count -= 3; 678 | } 679 | 680 | if (count >= 2) { 681 | if (numeric_tuple(data, ds, 7, 2) < 0) 682 | return QUIRC_ERROR_DATA_UNDERFLOW; 683 | count -= 2; 684 | } 685 | 686 | if (count) { 687 | if (numeric_tuple(data, ds, 4, 1) < 0) 688 | return QUIRC_ERROR_DATA_UNDERFLOW; 689 | count--; 690 | } 691 | 692 | return QUIRC_SUCCESS; 693 | } 694 | 695 | static int alpha_tuple(struct quirc_data *data, 696 | struct datastream *ds, 697 | int bits, int digits) 698 | { 699 | int tuple; 700 | int i; 701 | 702 | if (bits_remaining(ds) < bits) 703 | return -1; 704 | 705 | tuple = take_bits(ds, bits); 706 | 707 | for (i = 0; i < digits; i++) { 708 | static const char *alpha_map = 709 | "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; 710 | 711 | data->payload[data->payload_len + digits - i - 1] = 712 | alpha_map[tuple % 45]; 713 | tuple /= 45; 714 | } 715 | 716 | data->payload_len += digits; 717 | return 0; 718 | } 719 | 720 | static quirc_decode_error_t decode_alpha(struct quirc_data *data, 721 | struct datastream *ds) 722 | { 723 | int bits = 13; 724 | int count; 725 | 726 | if (data->version < 10) 727 | bits = 9; 728 | else if (data->version < 27) 729 | bits = 11; 730 | 731 | count = take_bits(ds, bits); 732 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 733 | return QUIRC_ERROR_DATA_OVERFLOW; 734 | 735 | while (count >= 2) { 736 | if (alpha_tuple(data, ds, 11, 2) < 0) 737 | return QUIRC_ERROR_DATA_UNDERFLOW; 738 | count -= 2; 739 | } 740 | 741 | if (count) { 742 | if (alpha_tuple(data, ds, 6, 1) < 0) 743 | return QUIRC_ERROR_DATA_UNDERFLOW; 744 | count--; 745 | } 746 | 747 | return QUIRC_SUCCESS; 748 | } 749 | 750 | static quirc_decode_error_t decode_byte(struct quirc_data *data, 751 | struct datastream *ds) 752 | { 753 | int bits = 16; 754 | int count; 755 | int i; 756 | 757 | if (data->version < 10) 758 | bits = 8; 759 | 760 | count = take_bits(ds, bits); 761 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 762 | return QUIRC_ERROR_DATA_OVERFLOW; 763 | if (bits_remaining(ds) < count * 8) 764 | return QUIRC_ERROR_DATA_UNDERFLOW; 765 | 766 | for (i = 0; i < count; i++) 767 | data->payload[data->payload_len++] = take_bits(ds, 8); 768 | 769 | return QUIRC_SUCCESS; 770 | } 771 | 772 | static quirc_decode_error_t decode_kanji(struct quirc_data *data, 773 | struct datastream *ds) 774 | { 775 | int bits = 12; 776 | int count; 777 | int i; 778 | 779 | if (data->version < 10) 780 | bits = 8; 781 | else if (data->version < 27) 782 | bits = 10; 783 | 784 | count = take_bits(ds, bits); 785 | if (data->payload_len + count * 2 + 1 > QUIRC_MAX_PAYLOAD) 786 | return QUIRC_ERROR_DATA_OVERFLOW; 787 | if (bits_remaining(ds) < count * 13) 788 | return QUIRC_ERROR_DATA_UNDERFLOW; 789 | 790 | for (i = 0; i < count; i++) { 791 | int d = take_bits(ds, 13); 792 | int msB = d / 0xc0; 793 | int lsB = d % 0xc0; 794 | int intermediate = (msB << 8) | lsB; 795 | uint16_t sjw; 796 | 797 | if (intermediate + 0x8140 <= 0x9ffc) { 798 | /* bytes are in the range 0x8140 to 0x9FFC */ 799 | sjw = intermediate + 0x8140; 800 | } else { 801 | /* bytes are in the range 0xE040 to 0xEBBF */ 802 | sjw = intermediate + 0xc140; 803 | } 804 | 805 | data->payload[data->payload_len++] = sjw >> 8; 806 | data->payload[data->payload_len++] = sjw & 0xff; 807 | } 808 | 809 | return QUIRC_SUCCESS; 810 | } 811 | 812 | static quirc_decode_error_t decode_eci(struct quirc_data *data, 813 | struct datastream *ds) 814 | { 815 | if (bits_remaining(ds) < 8) 816 | return QUIRC_ERROR_DATA_UNDERFLOW; 817 | 818 | data->eci = take_bits(ds, 8); 819 | 820 | if ((data->eci & 0xc0) == 0x80) { 821 | if (bits_remaining(ds) < 8) 822 | return QUIRC_ERROR_DATA_UNDERFLOW; 823 | 824 | data->eci = (data->eci << 8) | take_bits(ds, 8); 825 | } else if ((data->eci & 0xe0) == 0xc0) { 826 | if (bits_remaining(ds) < 16) 827 | return QUIRC_ERROR_DATA_UNDERFLOW; 828 | 829 | data->eci = (data->eci << 16) | take_bits(ds, 16); 830 | } 831 | 832 | return QUIRC_SUCCESS; 833 | } 834 | 835 | static quirc_decode_error_t decode_payload(struct quirc_data *data, 836 | struct datastream *ds) 837 | { 838 | while (bits_remaining(ds) >= 4) { 839 | quirc_decode_error_t err = QUIRC_SUCCESS; 840 | int type = take_bits(ds, 4); 841 | 842 | switch (type) { 843 | case QUIRC_DATA_TYPE_NUMERIC: 844 | err = decode_numeric(data, ds); 845 | break; 846 | 847 | case QUIRC_DATA_TYPE_ALPHA: 848 | err = decode_alpha(data, ds); 849 | break; 850 | 851 | case QUIRC_DATA_TYPE_BYTE: 852 | err = decode_byte(data, ds); 853 | break; 854 | 855 | case QUIRC_DATA_TYPE_KANJI: 856 | err = decode_kanji(data, ds); 857 | break; 858 | 859 | case 7: 860 | err = decode_eci(data, ds); 861 | break; 862 | 863 | default: 864 | goto done; 865 | } 866 | 867 | if (err) 868 | return err; 869 | 870 | if (!(type & (type - 1)) && (type > data->data_type)) 871 | data->data_type = type; 872 | } 873 | done: 874 | 875 | /* Add nul terminator to all payloads */ 876 | if (data->payload_len >= (int) sizeof(data->payload)) 877 | data->payload_len--; 878 | data->payload[data->payload_len] = 0; 879 | 880 | return QUIRC_SUCCESS; 881 | } 882 | 883 | quirc_decode_error_t quirc_decode(const struct quirc_code *code, 884 | struct quirc_data *data) 885 | { 886 | quirc_decode_error_t err; 887 | struct datastream ds; 888 | 889 | if ((code->size - 17) % 4) 890 | return QUIRC_ERROR_INVALID_GRID_SIZE; 891 | 892 | memset(data, 0, sizeof(*data)); 893 | memset(&ds, 0, sizeof(ds)); 894 | 895 | data->version = (code->size - 17) / 4; 896 | 897 | if (data->version < 1 || 898 | data->version > QUIRC_MAX_VERSION) 899 | return QUIRC_ERROR_INVALID_VERSION; 900 | 901 | /* Read format information -- try both locations */ 902 | err = read_format(code, data, 0); 903 | if (err) 904 | err = read_format(code, data, 1); 905 | if (err) 906 | return err; 907 | 908 | read_data(code, data, &ds); 909 | err = codestream_ecc(data, &ds); 910 | if (err) 911 | return err; 912 | 913 | err = decode_payload(data, &ds); 914 | if (err) 915 | return err; 916 | 917 | return QUIRC_SUCCESS; 918 | } 919 | 920 | void quirc_flip(struct quirc_code *code) 921 | { 922 | struct quirc_code flipped = {0}; 923 | unsigned int offset = 0; 924 | for (int y = 0; y < code->size; y++) { 925 | for (int x = 0; x < code->size; x++) { 926 | if (grid_bit(code, y, x)) { 927 | flipped.cell_bitmap[offset >> 3u] |= (1u << (offset & 7u)); 928 | } 929 | offset++; 930 | } 931 | } 932 | memcpy(&code->cell_bitmap, &flipped.cell_bitmap, sizeof(flipped.cell_bitmap)); 933 | } 934 | -------------------------------------------------------------------------------- /deps/quirc/identify.c: -------------------------------------------------------------------------------- 1 | /* quirc - QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "quirc_internal.h" 22 | 23 | /************************************************************************ 24 | * Linear algebra routines 25 | */ 26 | 27 | static int line_intersect(const struct quirc_point *p0, 28 | const struct quirc_point *p1, 29 | const struct quirc_point *q0, 30 | const struct quirc_point *q1, 31 | struct quirc_point *r) 32 | { 33 | /* (a, b) is perpendicular to line p */ 34 | int a = -(p1->y - p0->y); 35 | int b = p1->x - p0->x; 36 | 37 | /* (c, d) is perpendicular to line q */ 38 | int c = -(q1->y - q0->y); 39 | int d = q1->x - q0->x; 40 | 41 | /* e and f are dot products of the respective vectors with p and q */ 42 | int e = a * p1->x + b * p1->y; 43 | int f = c * q1->x + d * q1->y; 44 | 45 | /* Now we need to solve: 46 | * [a b] [rx] [e] 47 | * [c d] [ry] = [f] 48 | * 49 | * We do this by inverting the matrix and applying it to (e, f): 50 | * [ d -b] [e] [rx] 51 | * 1/det [-c a] [f] = [ry] 52 | */ 53 | int det = (a * d) - (b * c); 54 | 55 | if (!det) 56 | return 0; 57 | 58 | r->x = (d * e - b * f) / det; 59 | r->y = (-c * e + a * f) / det; 60 | 61 | return 1; 62 | } 63 | 64 | static void perspective_setup(double *c, 65 | const struct quirc_point *rect, 66 | double w, double h) 67 | { 68 | double x0 = rect[0].x; 69 | double y0 = rect[0].y; 70 | double x1 = rect[1].x; 71 | double y1 = rect[1].y; 72 | double x2 = rect[2].x; 73 | double y2 = rect[2].y; 74 | double x3 = rect[3].x; 75 | double y3 = rect[3].y; 76 | 77 | double wden = w * (x2*y3 - x3*y2 + (x3-x2)*y1 + x1*(y2-y3)); 78 | double hden = h * (x2*y3 + x1*(y2-y3) - x3*y2 + (x3-x2)*y1); 79 | 80 | c[0] = (x1*(x2*y3-x3*y2) + x0*(-x2*y3+x3*y2+(x2-x3)*y1) + 81 | x1*(x3-x2)*y0) / wden; 82 | c[1] = -(x0*(x2*y3+x1*(y2-y3)-x2*y1) - x1*x3*y2 + x2*x3*y1 83 | + (x1*x3-x2*x3)*y0) / hden; 84 | c[2] = x0; 85 | c[3] = (y0*(x1*(y3-y2)-x2*y3+x3*y2) + y1*(x2*y3-x3*y2) + 86 | x0*y1*(y2-y3)) / wden; 87 | c[4] = (x0*(y1*y3-y2*y3) + x1*y2*y3 - x2*y1*y3 + 88 | y0*(x3*y2-x1*y2+(x2-x3)*y1)) / hden; 89 | c[5] = y0; 90 | c[6] = (x1*(y3-y2) + x0*(y2-y3) + (x2-x3)*y1 + (x3-x2)*y0) / wden; 91 | c[7] = (-x2*y3 + x1*y3 + x3*y2 + x0*(y1-y2) - x3*y1 + (x2-x1)*y0) / 92 | hden; 93 | } 94 | 95 | static void perspective_map(const double *c, 96 | double u, double v, struct quirc_point *ret) 97 | { 98 | double den = c[6]*u + c[7]*v + 1.0; 99 | double x = (c[0]*u + c[1]*v + c[2]) / den; 100 | double y = (c[3]*u + c[4]*v + c[5]) / den; 101 | 102 | ret->x = (int) rint(x); 103 | ret->y = (int) rint(y); 104 | } 105 | 106 | static void perspective_unmap(const double *c, 107 | const struct quirc_point *in, 108 | double *u, double *v) 109 | { 110 | double x = in->x; 111 | double y = in->y; 112 | double den = -c[0]*c[7]*y + c[1]*c[6]*y + (c[3]*c[7]-c[4]*c[6])*x + 113 | c[0]*c[4] - c[1]*c[3]; 114 | 115 | *u = -(c[1]*(y-c[5]) - c[2]*c[7]*y + (c[5]*c[7]-c[4])*x + c[2]*c[4]) / 116 | den; 117 | *v = (c[0]*(y-c[5]) - c[2]*c[6]*y + (c[5]*c[6]-c[3])*x + c[2]*c[3]) / 118 | den; 119 | } 120 | 121 | /************************************************************************ 122 | * Span-based floodfill routine 123 | */ 124 | 125 | #define FLOOD_FILL_MAX_DEPTH 4096 126 | 127 | typedef void (*span_func_t)(void *user_data, int y, int left, int right); 128 | 129 | static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to, 130 | span_func_t func, void *user_data, 131 | int depth) 132 | { 133 | int left = x; 134 | int right = x; 135 | int i; 136 | quirc_pixel_t *row = q->pixels + y * q->w; 137 | 138 | if (depth >= FLOOD_FILL_MAX_DEPTH) 139 | return; 140 | 141 | while (left > 0 && row[left - 1] == from) 142 | left--; 143 | 144 | while (right < q->w - 1 && row[right + 1] == from) 145 | right++; 146 | 147 | /* Fill the extent */ 148 | for (i = left; i <= right; i++) 149 | row[i] = to; 150 | 151 | if (func) 152 | func(user_data, y, left, right); 153 | 154 | /* Seed new flood-fills */ 155 | if (y > 0) { 156 | row = q->pixels + (y - 1) * q->w; 157 | 158 | for (i = left; i <= right; i++) 159 | if (row[i] == from) 160 | flood_fill_seed(q, i, y - 1, from, to, 161 | func, user_data, depth + 1); 162 | } 163 | 164 | if (y < q->h - 1) { 165 | row = q->pixels + (y + 1) * q->w; 166 | 167 | for (i = left; i <= right; i++) 168 | if (row[i] == from) 169 | flood_fill_seed(q, i, y + 1, from, to, 170 | func, user_data, depth + 1); 171 | } 172 | } 173 | 174 | /************************************************************************ 175 | * Adaptive thresholding 176 | */ 177 | 178 | static uint8_t otsu(const struct quirc *q) 179 | { 180 | int numPixels = q->w * q->h; 181 | 182 | // Calculate histogram 183 | unsigned int histogram[UINT8_MAX + 1]; 184 | (void)memset(histogram, 0, sizeof(histogram)); 185 | uint8_t* ptr = q->image; 186 | int length = numPixels; 187 | while (length--) { 188 | uint8_t value = *ptr++; 189 | histogram[value]++; 190 | } 191 | 192 | // Calculate weighted sum of histogram values 193 | unsigned int sum = 0; 194 | unsigned int i = 0; 195 | for (i = 0; i <= UINT8_MAX; ++i) { 196 | sum += i * histogram[i]; 197 | } 198 | 199 | // Compute threshold 200 | int sumB = 0; 201 | int q1 = 0; 202 | double max = 0; 203 | uint8_t threshold = 0; 204 | for (i = 0; i <= UINT8_MAX; ++i) { 205 | // Weighted background 206 | q1 += histogram[i]; 207 | if (q1 == 0) 208 | continue; 209 | 210 | // Weighted foreground 211 | const int q2 = numPixels - q1; 212 | if (q2 == 0) 213 | break; 214 | 215 | sumB += i * histogram[i]; 216 | const double m1 = (double)sumB / q1; 217 | const double m2 = ((double)sum - sumB) / q2; 218 | const double m1m2 = m1 - m2; 219 | const double variance = m1m2 * m1m2 * q1 * q2; 220 | if (variance >= max) { 221 | threshold = i; 222 | max = variance; 223 | } 224 | } 225 | 226 | return threshold; 227 | } 228 | 229 | static void area_count(void *user_data, int y, int left, int right) 230 | { 231 | ((struct quirc_region *)user_data)->count += right - left + 1; 232 | } 233 | 234 | static int region_code(struct quirc *q, int x, int y) 235 | { 236 | int pixel; 237 | struct quirc_region *box; 238 | int region; 239 | 240 | if (x < 0 || y < 0 || x >= q->w || y >= q->h) 241 | return -1; 242 | 243 | pixel = q->pixels[y * q->w + x]; 244 | 245 | if (pixel >= QUIRC_PIXEL_REGION) 246 | return pixel; 247 | 248 | if (pixel == QUIRC_PIXEL_WHITE) 249 | return -1; 250 | 251 | if (q->num_regions >= QUIRC_MAX_REGIONS) 252 | return -1; 253 | 254 | region = q->num_regions; 255 | box = &q->regions[q->num_regions++]; 256 | 257 | memset(box, 0, sizeof(*box)); 258 | 259 | box->seed.x = x; 260 | box->seed.y = y; 261 | box->capstone = -1; 262 | 263 | flood_fill_seed(q, x, y, pixel, region, area_count, box, 0); 264 | 265 | return region; 266 | } 267 | 268 | struct polygon_score_data { 269 | struct quirc_point ref; 270 | 271 | int scores[4]; 272 | struct quirc_point *corners; 273 | }; 274 | 275 | static void find_one_corner(void *user_data, int y, int left, int right) 276 | { 277 | struct polygon_score_data *psd = 278 | (struct polygon_score_data *)user_data; 279 | int xs[2] = {left, right}; 280 | int dy = y - psd->ref.y; 281 | int i; 282 | 283 | for (i = 0; i < 2; i++) { 284 | int dx = xs[i] - psd->ref.x; 285 | int d = dx * dx + dy * dy; 286 | 287 | if (d > psd->scores[0]) { 288 | psd->scores[0] = d; 289 | psd->corners[0].x = xs[i]; 290 | psd->corners[0].y = y; 291 | } 292 | } 293 | } 294 | 295 | static void find_other_corners(void *user_data, int y, int left, int right) 296 | { 297 | struct polygon_score_data *psd = 298 | (struct polygon_score_data *)user_data; 299 | int xs[2] = {left, right}; 300 | int i; 301 | 302 | for (i = 0; i < 2; i++) { 303 | int up = xs[i] * psd->ref.x + y * psd->ref.y; 304 | int right = xs[i] * -psd->ref.y + y * psd->ref.x; 305 | int scores[4] = {up, right, -up, -right}; 306 | int j; 307 | 308 | for (j = 0; j < 4; j++) { 309 | if (scores[j] > psd->scores[j]) { 310 | psd->scores[j] = scores[j]; 311 | psd->corners[j].x = xs[i]; 312 | psd->corners[j].y = y; 313 | } 314 | } 315 | } 316 | } 317 | 318 | static void find_region_corners(struct quirc *q, 319 | int rcode, const struct quirc_point *ref, 320 | struct quirc_point *corners) 321 | { 322 | struct quirc_region *region = &q->regions[rcode]; 323 | struct polygon_score_data psd; 324 | int i; 325 | 326 | memset(&psd, 0, sizeof(psd)); 327 | psd.corners = corners; 328 | 329 | memcpy(&psd.ref, ref, sizeof(psd.ref)); 330 | psd.scores[0] = -1; 331 | flood_fill_seed(q, region->seed.x, region->seed.y, 332 | rcode, QUIRC_PIXEL_BLACK, 333 | find_one_corner, &psd, 0); 334 | 335 | psd.ref.x = psd.corners[0].x - psd.ref.x; 336 | psd.ref.y = psd.corners[0].y - psd.ref.y; 337 | 338 | for (i = 0; i < 4; i++) 339 | memcpy(&psd.corners[i], ®ion->seed, 340 | sizeof(psd.corners[i])); 341 | 342 | i = region->seed.x * psd.ref.x + region->seed.y * psd.ref.y; 343 | psd.scores[0] = i; 344 | psd.scores[2] = -i; 345 | i = region->seed.x * -psd.ref.y + region->seed.y * psd.ref.x; 346 | psd.scores[1] = i; 347 | psd.scores[3] = -i; 348 | 349 | flood_fill_seed(q, region->seed.x, region->seed.y, 350 | QUIRC_PIXEL_BLACK, rcode, 351 | find_other_corners, &psd, 0); 352 | } 353 | 354 | static void record_capstone(struct quirc *q, int ring, int stone) 355 | { 356 | struct quirc_region *stone_reg = &q->regions[stone]; 357 | struct quirc_region *ring_reg = &q->regions[ring]; 358 | struct quirc_capstone *capstone; 359 | int cs_index; 360 | 361 | if (q->num_capstones >= QUIRC_MAX_CAPSTONES) 362 | return; 363 | 364 | cs_index = q->num_capstones; 365 | capstone = &q->capstones[q->num_capstones++]; 366 | 367 | memset(capstone, 0, sizeof(*capstone)); 368 | 369 | capstone->qr_grid = -1; 370 | capstone->ring = ring; 371 | capstone->stone = stone; 372 | stone_reg->capstone = cs_index; 373 | ring_reg->capstone = cs_index; 374 | 375 | /* Find the corners of the ring */ 376 | find_region_corners(q, ring, &stone_reg->seed, capstone->corners); 377 | 378 | /* Set up the perspective transform and find the center */ 379 | perspective_setup(capstone->c, capstone->corners, 7.0, 7.0); 380 | perspective_map(capstone->c, 3.5, 3.5, &capstone->center); 381 | } 382 | 383 | static void test_capstone(struct quirc *q, int x, int y, int *pb) 384 | { 385 | int ring_right = region_code(q, x - pb[4], y); 386 | int stone = region_code(q, x - pb[4] - pb[3] - pb[2], y); 387 | int ring_left = region_code(q, x - pb[4] - pb[3] - 388 | pb[2] - pb[1] - pb[0], 389 | y); 390 | struct quirc_region *stone_reg; 391 | struct quirc_region *ring_reg; 392 | int ratio; 393 | 394 | if (ring_left < 0 || ring_right < 0 || stone < 0) 395 | return; 396 | 397 | /* Left and ring of ring should be connected */ 398 | if (ring_left != ring_right) 399 | return; 400 | 401 | /* Ring should be disconnected from stone */ 402 | if (ring_left == stone) 403 | return; 404 | 405 | stone_reg = &q->regions[stone]; 406 | ring_reg = &q->regions[ring_left]; 407 | 408 | /* Already detected */ 409 | if (stone_reg->capstone >= 0 || ring_reg->capstone >= 0) 410 | return; 411 | 412 | /* Ratio should ideally be 37.5 */ 413 | ratio = stone_reg->count * 100 / ring_reg->count; 414 | if (ratio < 10 || ratio > 70) 415 | return; 416 | 417 | record_capstone(q, ring_left, stone); 418 | } 419 | 420 | static void finder_scan(struct quirc *q, int y) 421 | { 422 | quirc_pixel_t *row = q->pixels + y * q->w; 423 | int x; 424 | int last_color = 0; 425 | int run_length = 0; 426 | int run_count = 0; 427 | int pb[5]; 428 | 429 | memset(pb, 0, sizeof(pb)); 430 | for (x = 0; x < q->w; x++) { 431 | int color = row[x] ? 1 : 0; 432 | 433 | if (x && color != last_color) { 434 | memmove(pb, pb + 1, sizeof(pb[0]) * 4); 435 | pb[4] = run_length; 436 | run_length = 0; 437 | run_count++; 438 | 439 | if (!color && run_count >= 5) { 440 | static int check[5] = {1, 1, 3, 1, 1}; 441 | int avg, err; 442 | int i; 443 | int ok = 1; 444 | 445 | avg = (pb[0] + pb[1] + pb[3] + pb[4]) / 4; 446 | err = avg * 3 / 4; 447 | 448 | for (i = 0; i < 5; i++) 449 | if (pb[i] < check[i] * avg - err || 450 | pb[i] > check[i] * avg + err) 451 | ok = 0; 452 | 453 | if (ok) 454 | test_capstone(q, x, y, pb); 455 | } 456 | } 457 | 458 | run_length++; 459 | last_color = color; 460 | } 461 | } 462 | 463 | static void find_alignment_pattern(struct quirc *q, int index) 464 | { 465 | struct quirc_grid *qr = &q->grids[index]; 466 | struct quirc_capstone *c0 = &q->capstones[qr->caps[0]]; 467 | struct quirc_capstone *c2 = &q->capstones[qr->caps[2]]; 468 | struct quirc_point a; 469 | struct quirc_point b; 470 | struct quirc_point c; 471 | int size_estimate; 472 | int step_size = 1; 473 | int dir = 0; 474 | double u, v; 475 | 476 | /* Grab our previous estimate of the alignment pattern corner */ 477 | memcpy(&b, &qr->align, sizeof(b)); 478 | 479 | /* Guess another two corners of the alignment pattern so that we 480 | * can estimate its size. 481 | */ 482 | perspective_unmap(c0->c, &b, &u, &v); 483 | perspective_map(c0->c, u, v + 1.0, &a); 484 | perspective_unmap(c2->c, &b, &u, &v); 485 | perspective_map(c2->c, u + 1.0, v, &c); 486 | 487 | size_estimate = abs((a.x - b.x) * -(c.y - b.y) + 488 | (a.y - b.y) * (c.x - b.x)); 489 | 490 | /* Spiral outwards from the estimate point until we find something 491 | * roughly the right size. Don't look too far from the estimate 492 | * point. 493 | */ 494 | while (step_size * step_size < size_estimate * 100) { 495 | static const int dx_map[] = {1, 0, -1, 0}; 496 | static const int dy_map[] = {0, -1, 0, 1}; 497 | int i; 498 | 499 | for (i = 0; i < step_size; i++) { 500 | int code = region_code(q, b.x, b.y); 501 | 502 | if (code >= 0) { 503 | struct quirc_region *reg = &q->regions[code]; 504 | 505 | if (reg->count >= size_estimate / 2 && 506 | reg->count <= size_estimate * 2) { 507 | qr->align_region = code; 508 | return; 509 | } 510 | } 511 | 512 | b.x += dx_map[dir]; 513 | b.y += dy_map[dir]; 514 | } 515 | 516 | dir = (dir + 1) % 4; 517 | if (!(dir & 1)) 518 | step_size++; 519 | } 520 | } 521 | 522 | static void find_leftmost_to_line(void *user_data, int y, int left, int right) 523 | { 524 | struct polygon_score_data *psd = 525 | (struct polygon_score_data *)user_data; 526 | int xs[2] = {left, right}; 527 | int i; 528 | 529 | for (i = 0; i < 2; i++) { 530 | int d = -psd->ref.y * xs[i] + psd->ref.x * y; 531 | 532 | if (d < psd->scores[0]) { 533 | psd->scores[0] = d; 534 | psd->corners[0].x = xs[i]; 535 | psd->corners[0].y = y; 536 | } 537 | } 538 | } 539 | 540 | /* Do a Bresenham scan from one point to another and count the number 541 | * of black/white transitions. 542 | */ 543 | static int timing_scan(const struct quirc *q, 544 | const struct quirc_point *p0, 545 | const struct quirc_point *p1) 546 | { 547 | int n = p1->x - p0->x; 548 | int d = p1->y - p0->y; 549 | int x = p0->x; 550 | int y = p0->y; 551 | int *dom, *nondom; 552 | int dom_step; 553 | int nondom_step; 554 | int a = 0; 555 | int i; 556 | int run_length = 0; 557 | int count = 0; 558 | 559 | if (p0->x < 0 || p0->y < 0 || p0->x >= q->w || p0->y >= q->h) 560 | return -1; 561 | if (p1->x < 0 || p1->y < 0 || p1->x >= q->w || p1->y >= q->h) 562 | return -1; 563 | 564 | if (abs(n) > abs(d)) { 565 | int swap = n; 566 | 567 | n = d; 568 | d = swap; 569 | 570 | dom = &x; 571 | nondom = &y; 572 | } else { 573 | dom = &y; 574 | nondom = &x; 575 | } 576 | 577 | if (n < 0) { 578 | n = -n; 579 | nondom_step = -1; 580 | } else { 581 | nondom_step = 1; 582 | } 583 | 584 | if (d < 0) { 585 | d = -d; 586 | dom_step = -1; 587 | } else { 588 | dom_step = 1; 589 | } 590 | 591 | x = p0->x; 592 | y = p0->y; 593 | for (i = 0; i <= d; i++) { 594 | int pixel; 595 | 596 | if (y < 0 || y >= q->h || x < 0 || x >= q->w) 597 | break; 598 | 599 | pixel = q->pixels[y * q->w + x]; 600 | 601 | if (pixel) { 602 | if (run_length >= 2) 603 | count++; 604 | run_length = 0; 605 | } else { 606 | run_length++; 607 | } 608 | 609 | a += n; 610 | *dom += dom_step; 611 | if (a >= d) { 612 | *nondom += nondom_step; 613 | a -= d; 614 | } 615 | } 616 | 617 | return count; 618 | } 619 | 620 | /* Try the measure the timing pattern for a given QR code. This does 621 | * not require the global perspective to have been set up, but it 622 | * does require that the capstone corners have been set to their 623 | * canonical rotation. 624 | * 625 | * For each capstone, we find a point in the middle of the ring band 626 | * which is nearest the centre of the code. Using these points, we do 627 | * a horizontal and a vertical timing scan. 628 | */ 629 | static int measure_timing_pattern(struct quirc *q, int index) 630 | { 631 | struct quirc_grid *qr = &q->grids[index]; 632 | int i; 633 | int scan; 634 | int ver; 635 | int size; 636 | 637 | for (i = 0; i < 3; i++) { 638 | static const double us[] = {6.5, 6.5, 0.5}; 639 | static const double vs[] = {0.5, 6.5, 6.5}; 640 | struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; 641 | 642 | perspective_map(cap->c, us[i], vs[i], &qr->tpep[i]); 643 | } 644 | 645 | qr->hscan = timing_scan(q, &qr->tpep[1], &qr->tpep[2]); 646 | qr->vscan = timing_scan(q, &qr->tpep[1], &qr->tpep[0]); 647 | 648 | scan = qr->hscan; 649 | if (qr->vscan > scan) 650 | scan = qr->vscan; 651 | 652 | /* If neither scan worked, we can't go any further. */ 653 | if (scan < 0) 654 | return -1; 655 | 656 | /* Choose the nearest allowable grid size */ 657 | size = scan * 2 + 13; 658 | ver = (size - 15) / 4; 659 | if (ver > QUIRC_MAX_VERSION) { 660 | return -1; 661 | } 662 | 663 | qr->grid_size = ver * 4 + 17; 664 | return 0; 665 | } 666 | 667 | /* Read a cell from a grid using the currently set perspective 668 | * transform. Returns +/- 1 for black/white, 0 for cells which are 669 | * out of image bounds. 670 | */ 671 | static int read_cell(const struct quirc *q, int index, int x, int y) 672 | { 673 | const struct quirc_grid *qr = &q->grids[index]; 674 | struct quirc_point p; 675 | 676 | perspective_map(qr->c, x + 0.5, y + 0.5, &p); 677 | if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w) 678 | return 0; 679 | 680 | return q->pixels[p.y * q->w + p.x] ? 1 : -1; 681 | } 682 | 683 | static int fitness_cell(const struct quirc *q, int index, int x, int y) 684 | { 685 | const struct quirc_grid *qr = &q->grids[index]; 686 | int score = 0; 687 | int u, v; 688 | 689 | for (v = 0; v < 3; v++) 690 | for (u = 0; u < 3; u++) { 691 | static const double offsets[] = {0.3, 0.5, 0.7}; 692 | struct quirc_point p; 693 | 694 | perspective_map(qr->c, x + offsets[u], 695 | y + offsets[v], &p); 696 | if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w) 697 | continue; 698 | 699 | if (q->pixels[p.y * q->w + p.x]) 700 | score++; 701 | else 702 | score--; 703 | } 704 | 705 | return score; 706 | } 707 | 708 | static int fitness_ring(const struct quirc *q, int index, int cx, int cy, 709 | int radius) 710 | { 711 | int i; 712 | int score = 0; 713 | 714 | for (i = 0; i < radius * 2; i++) { 715 | score += fitness_cell(q, index, cx - radius + i, cy - radius); 716 | score += fitness_cell(q, index, cx - radius, cy + radius - i); 717 | score += fitness_cell(q, index, cx + radius, cy - radius + i); 718 | score += fitness_cell(q, index, cx + radius - i, cy + radius); 719 | } 720 | 721 | return score; 722 | } 723 | 724 | static int fitness_apat(const struct quirc *q, int index, int cx, int cy) 725 | { 726 | return fitness_cell(q, index, cx, cy) - 727 | fitness_ring(q, index, cx, cy, 1) + 728 | fitness_ring(q, index, cx, cy, 2); 729 | } 730 | 731 | static int fitness_capstone(const struct quirc *q, int index, int x, int y) 732 | { 733 | x += 3; 734 | y += 3; 735 | 736 | return fitness_cell(q, index, x, y) + 737 | fitness_ring(q, index, x, y, 1) - 738 | fitness_ring(q, index, x, y, 2) + 739 | fitness_ring(q, index, x, y, 3); 740 | } 741 | 742 | /* Compute a fitness score for the currently configured perspective 743 | * transform, using the features we expect to find by scanning the 744 | * grid. 745 | */ 746 | static int fitness_all(const struct quirc *q, int index) 747 | { 748 | const struct quirc_grid *qr = &q->grids[index]; 749 | int version = (qr->grid_size - 17) / 4; 750 | const struct quirc_version_info *info = &quirc_version_db[version]; 751 | int score = 0; 752 | int i, j; 753 | int ap_count; 754 | 755 | /* Check the timing pattern */ 756 | for (i = 0; i < qr->grid_size - 14; i++) { 757 | int expect = (i & 1) ? 1 : -1; 758 | 759 | score += fitness_cell(q, index, i + 7, 6) * expect; 760 | score += fitness_cell(q, index, 6, i + 7) * expect; 761 | } 762 | 763 | /* Check capstones */ 764 | score += fitness_capstone(q, index, 0, 0); 765 | score += fitness_capstone(q, index, qr->grid_size - 7, 0); 766 | score += fitness_capstone(q, index, 0, qr->grid_size - 7); 767 | 768 | if (version < 0 || version > QUIRC_MAX_VERSION) 769 | return score; 770 | 771 | /* Check alignment patterns */ 772 | ap_count = 0; 773 | while ((ap_count < QUIRC_MAX_ALIGNMENT) && info->apat[ap_count]) 774 | ap_count++; 775 | 776 | for (i = 1; i + 1 < ap_count; i++) { 777 | score += fitness_apat(q, index, 6, info->apat[i]); 778 | score += fitness_apat(q, index, info->apat[i], 6); 779 | } 780 | 781 | for (i = 1; i < ap_count; i++) 782 | for (j = 1; j < ap_count; j++) 783 | score += fitness_apat(q, index, 784 | info->apat[i], info->apat[j]); 785 | 786 | return score; 787 | } 788 | 789 | static void jiggle_perspective(struct quirc *q, int index) 790 | { 791 | struct quirc_grid *qr = &q->grids[index]; 792 | int best = fitness_all(q, index); 793 | int pass; 794 | double adjustments[8]; 795 | int i; 796 | 797 | for (i = 0; i < 8; i++) 798 | adjustments[i] = qr->c[i] * 0.02; 799 | 800 | for (pass = 0; pass < 5; pass++) { 801 | for (i = 0; i < 16; i++) { 802 | int j = i >> 1; 803 | int test; 804 | double old = qr->c[j]; 805 | double step = adjustments[j]; 806 | double new; 807 | 808 | if (i & 1) 809 | new = old + step; 810 | else 811 | new = old - step; 812 | 813 | qr->c[j] = new; 814 | test = fitness_all(q, index); 815 | 816 | if (test > best) 817 | best = test; 818 | else 819 | qr->c[j] = old; 820 | } 821 | 822 | for (i = 0; i < 8; i++) 823 | adjustments[i] *= 0.5; 824 | } 825 | } 826 | 827 | /* Once the capstones are in place and an alignment point has been 828 | * chosen, we call this function to set up a grid-reading perspective 829 | * transform. 830 | */ 831 | static void setup_qr_perspective(struct quirc *q, int index) 832 | { 833 | struct quirc_grid *qr = &q->grids[index]; 834 | struct quirc_point rect[4]; 835 | 836 | /* Set up the perspective map for reading the grid */ 837 | memcpy(&rect[0], &q->capstones[qr->caps[1]].corners[0], 838 | sizeof(rect[0])); 839 | memcpy(&rect[1], &q->capstones[qr->caps[2]].corners[0], 840 | sizeof(rect[0])); 841 | memcpy(&rect[2], &qr->align, sizeof(rect[0])); 842 | memcpy(&rect[3], &q->capstones[qr->caps[0]].corners[0], 843 | sizeof(rect[0])); 844 | perspective_setup(qr->c, rect, qr->grid_size - 7, qr->grid_size - 7); 845 | 846 | jiggle_perspective(q, index); 847 | } 848 | 849 | /* Rotate the capstone with so that corner 0 is the leftmost with respect 850 | * to the given reference line. 851 | */ 852 | static void rotate_capstone(struct quirc_capstone *cap, 853 | const struct quirc_point *h0, 854 | const struct quirc_point *hd) 855 | { 856 | struct quirc_point copy[4]; 857 | int j; 858 | int best = 0; 859 | int best_score = INT_MAX; 860 | 861 | for (j = 0; j < 4; j++) { 862 | struct quirc_point *p = &cap->corners[j]; 863 | int score = (p->x - h0->x) * -hd->y + 864 | (p->y - h0->y) * hd->x; 865 | 866 | if (!j || score < best_score) { 867 | best = j; 868 | best_score = score; 869 | } 870 | } 871 | 872 | /* Rotate the capstone */ 873 | for (j = 0; j < 4; j++) 874 | memcpy(©[j], &cap->corners[(j + best) % 4], 875 | sizeof(copy[j])); 876 | memcpy(cap->corners, copy, sizeof(cap->corners)); 877 | perspective_setup(cap->c, cap->corners, 7.0, 7.0); 878 | } 879 | 880 | static void record_qr_grid(struct quirc *q, int a, int b, int c) 881 | { 882 | struct quirc_point h0, hd; 883 | int i; 884 | int qr_index; 885 | struct quirc_grid *qr; 886 | 887 | if (q->num_grids >= QUIRC_MAX_GRIDS) 888 | return; 889 | 890 | /* Construct the hypotenuse line from A to C. B should be to 891 | * the left of this line. 892 | */ 893 | memcpy(&h0, &q->capstones[a].center, sizeof(h0)); 894 | hd.x = q->capstones[c].center.x - q->capstones[a].center.x; 895 | hd.y = q->capstones[c].center.y - q->capstones[a].center.y; 896 | 897 | /* Make sure A-B-C is clockwise */ 898 | if ((q->capstones[b].center.x - h0.x) * -hd.y + 899 | (q->capstones[b].center.y - h0.y) * hd.x > 0) { 900 | int swap = a; 901 | 902 | a = c; 903 | c = swap; 904 | hd.x = -hd.x; 905 | hd.y = -hd.y; 906 | } 907 | 908 | /* Record the grid and its components */ 909 | qr_index = q->num_grids; 910 | qr = &q->grids[q->num_grids++]; 911 | 912 | memset(qr, 0, sizeof(*qr)); 913 | qr->caps[0] = a; 914 | qr->caps[1] = b; 915 | qr->caps[2] = c; 916 | qr->align_region = -1; 917 | 918 | /* Rotate each capstone so that corner 0 is top-left with respect 919 | * to the grid. 920 | */ 921 | for (i = 0; i < 3; i++) { 922 | struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; 923 | 924 | rotate_capstone(cap, &h0, &hd); 925 | cap->qr_grid = qr_index; 926 | } 927 | 928 | /* Check the timing pattern. This doesn't require a perspective 929 | * transform. 930 | */ 931 | if (measure_timing_pattern(q, qr_index) < 0) 932 | goto fail; 933 | 934 | /* Make an estimate based for the alignment pattern based on extending 935 | * lines from capstones A and C. 936 | */ 937 | if (!line_intersect(&q->capstones[a].corners[0], 938 | &q->capstones[a].corners[1], 939 | &q->capstones[c].corners[0], 940 | &q->capstones[c].corners[3], 941 | &qr->align)) 942 | goto fail; 943 | 944 | /* On V2+ grids, we should use the alignment pattern. */ 945 | if (qr->grid_size > 21) { 946 | /* Try to find the actual location of the alignment pattern. */ 947 | find_alignment_pattern(q, qr_index); 948 | 949 | /* Find the point of the alignment pattern closest to the 950 | * top-left of the QR grid. 951 | */ 952 | if (qr->align_region >= 0) { 953 | struct polygon_score_data psd; 954 | struct quirc_region *reg = 955 | &q->regions[qr->align_region]; 956 | 957 | /* Start from some point inside the alignment pattern */ 958 | memcpy(&qr->align, ®->seed, sizeof(qr->align)); 959 | 960 | memcpy(&psd.ref, &hd, sizeof(psd.ref)); 961 | psd.corners = &qr->align; 962 | psd.scores[0] = -hd.y * qr->align.x + 963 | hd.x * qr->align.y; 964 | 965 | flood_fill_seed(q, reg->seed.x, reg->seed.y, 966 | qr->align_region, QUIRC_PIXEL_BLACK, 967 | NULL, NULL, 0); 968 | flood_fill_seed(q, reg->seed.x, reg->seed.y, 969 | QUIRC_PIXEL_BLACK, qr->align_region, 970 | find_leftmost_to_line, &psd, 0); 971 | } 972 | } 973 | 974 | setup_qr_perspective(q, qr_index); 975 | return; 976 | 977 | fail: 978 | /* We've been unable to complete setup for this grid. Undo what we've 979 | * recorded and pretend it never happened. 980 | */ 981 | for (i = 0; i < 3; i++) 982 | q->capstones[qr->caps[i]].qr_grid = -1; 983 | q->num_grids--; 984 | } 985 | 986 | struct neighbour { 987 | int index; 988 | double distance; 989 | }; 990 | 991 | struct neighbour_list { 992 | struct neighbour n[QUIRC_MAX_CAPSTONES]; 993 | int count; 994 | }; 995 | 996 | static void test_neighbours(struct quirc *q, int i, 997 | const struct neighbour_list *hlist, 998 | const struct neighbour_list *vlist) 999 | { 1000 | int j, k; 1001 | double best_score = 0.0; 1002 | int best_h = -1, best_v = -1; 1003 | 1004 | /* Test each possible grouping */ 1005 | for (j = 0; j < hlist->count; j++) 1006 | for (k = 0; k < vlist->count; k++) { 1007 | const struct neighbour *hn = &hlist->n[j]; 1008 | const struct neighbour *vn = &vlist->n[k]; 1009 | double score = fabs(1.0 - hn->distance / vn->distance); 1010 | 1011 | if (score > 2.5) 1012 | continue; 1013 | 1014 | if (best_h < 0 || score < best_score) { 1015 | best_h = hn->index; 1016 | best_v = vn->index; 1017 | best_score = score; 1018 | } 1019 | } 1020 | 1021 | if (best_h < 0 || best_v < 0) 1022 | return; 1023 | 1024 | record_qr_grid(q, best_h, i, best_v); 1025 | } 1026 | 1027 | static void test_grouping(struct quirc *q, int i) 1028 | { 1029 | struct quirc_capstone *c1 = &q->capstones[i]; 1030 | int j; 1031 | struct neighbour_list hlist; 1032 | struct neighbour_list vlist; 1033 | 1034 | if (c1->qr_grid >= 0) 1035 | return; 1036 | 1037 | hlist.count = 0; 1038 | vlist.count = 0; 1039 | 1040 | /* Look for potential neighbours by examining the relative gradients 1041 | * from this capstone to others. 1042 | */ 1043 | for (j = 0; j < q->num_capstones; j++) { 1044 | struct quirc_capstone *c2 = &q->capstones[j]; 1045 | double u, v; 1046 | 1047 | if (i == j || c2->qr_grid >= 0) 1048 | continue; 1049 | 1050 | perspective_unmap(c1->c, &c2->center, &u, &v); 1051 | 1052 | u = fabs(u - 3.5); 1053 | v = fabs(v - 3.5); 1054 | 1055 | if (u < 0.2 * v) { 1056 | struct neighbour *n = &hlist.n[hlist.count++]; 1057 | 1058 | n->index = j; 1059 | n->distance = v; 1060 | } 1061 | 1062 | if (v < 0.2 * u) { 1063 | struct neighbour *n = &vlist.n[vlist.count++]; 1064 | 1065 | n->index = j; 1066 | n->distance = u; 1067 | } 1068 | } 1069 | 1070 | if (!(hlist.count && vlist.count)) 1071 | return; 1072 | 1073 | test_neighbours(q, i, &hlist, &vlist); 1074 | } 1075 | 1076 | static void pixels_setup(struct quirc *q, uint8_t threshold) 1077 | { 1078 | if (QUIRC_PIXEL_ALIAS_IMAGE) { 1079 | q->pixels = (quirc_pixel_t *)q->image; 1080 | } 1081 | 1082 | uint8_t* source = q->image; 1083 | quirc_pixel_t* dest = q->pixels; 1084 | int length = q->w * q->h; 1085 | while (length--) { 1086 | uint8_t value = *source++; 1087 | *dest++ = (value < threshold) ? QUIRC_PIXEL_BLACK : QUIRC_PIXEL_WHITE; 1088 | } 1089 | } 1090 | 1091 | uint8_t *quirc_begin(struct quirc *q, int *w, int *h) 1092 | { 1093 | q->num_regions = QUIRC_PIXEL_REGION; 1094 | q->num_capstones = 0; 1095 | q->num_grids = 0; 1096 | 1097 | if (w) 1098 | *w = q->w; 1099 | if (h) 1100 | *h = q->h; 1101 | 1102 | return q->image; 1103 | } 1104 | 1105 | void quirc_end(struct quirc *q) 1106 | { 1107 | int i; 1108 | 1109 | uint8_t threshold = otsu(q); 1110 | pixels_setup(q, threshold); 1111 | 1112 | for (i = 0; i < q->h; i++) 1113 | finder_scan(q, i); 1114 | 1115 | for (i = 0; i < q->num_capstones; i++) 1116 | test_grouping(q, i); 1117 | } 1118 | 1119 | void quirc_extract(const struct quirc *q, int index, 1120 | struct quirc_code *code) 1121 | { 1122 | const struct quirc_grid *qr = &q->grids[index]; 1123 | int y; 1124 | int i = 0; 1125 | 1126 | if (index < 0 || index > q->num_grids) 1127 | return; 1128 | 1129 | memset(code, 0, sizeof(*code)); 1130 | 1131 | perspective_map(qr->c, 0.0, 0.0, &code->corners[0]); 1132 | perspective_map(qr->c, qr->grid_size, 0.0, &code->corners[1]); 1133 | perspective_map(qr->c, qr->grid_size, qr->grid_size, 1134 | &code->corners[2]); 1135 | perspective_map(qr->c, 0.0, qr->grid_size, &code->corners[3]); 1136 | 1137 | code->size = qr->grid_size; 1138 | 1139 | for (y = 0; y < qr->grid_size; y++) { 1140 | int x; 1141 | for (x = 0; x < qr->grid_size; x++) { 1142 | if (read_cell(q, index, x, y) > 0) { 1143 | code->cell_bitmap[i >> 3] |= (1 << (i & 7)); 1144 | } 1145 | i++; 1146 | } 1147 | } 1148 | } 1149 | -------------------------------------------------------------------------------- /test/data/generated/qrcodegen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QR Code generator library (C) 3 | * 4 | * Copyright (c) Project Nayuki. (MIT License) 5 | * https://www.nayuki.io/page/qr-code-generator-library 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * - The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * - The Software is provided "as is", without warranty of any kind, express or 16 | * implied, including but not limited to the warranties of merchantability, 17 | * fitness for a particular purpose and noninfringement. In no event shall the 18 | * authors or copyright holders be liable for any claim, damages or other 19 | * liability, whether in an action of contract, tort or otherwise, arising from, 20 | * out of or in connection with the Software or the use or other dealings in the 21 | * Software. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "qrcodegen.h" 29 | 30 | #ifndef QRCODEGEN_TEST 31 | #define testable static // Keep functions private 32 | #else 33 | #define testable // Expose private functions 34 | #endif 35 | 36 | 37 | /*---- Forward declarations for private functions ----*/ 38 | 39 | // Regarding all public and private functions defined in this source file: 40 | // - They require all pointer/array arguments to be not null unless the array length is zero. 41 | // - They only read input scalar/array arguments, write to output pointer/array 42 | // arguments, and return scalar values; they are "pure" functions. 43 | // - They don't read mutable global variables or write to any global variables. 44 | // - They don't perform I/O, read the clock, print to console, etc. 45 | // - They allocate a small and constant amount of stack memory. 46 | // - They don't allocate or free any memory on the heap. 47 | // - They don't recurse or mutually recurse. All the code 48 | // could be inlined into the top-level public functions. 49 | // - They run in at most quadratic time with respect to input arguments. 50 | // Most functions run in linear time, and some in constant time. 51 | // There are no unbounded loops or non-obvious termination conditions. 52 | // - They are completely thread-safe if the caller does not give the 53 | // same writable buffer to concurrent calls to these functions. 54 | 55 | testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen); 56 | 57 | testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]); 58 | testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); 59 | testable int getNumRawDataModules(int ver); 60 | 61 | testable void reedSolomonComputeDivisor(int degree, uint8_t result[]); 62 | testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, 63 | const uint8_t generator[], int degree, uint8_t result[]); 64 | testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y); 65 | 66 | testable void initializeFunctionModules(int version, uint8_t qrcode[]); 67 | static void drawWhiteFunctionModules(uint8_t qrcode[], int version); 68 | static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]); 69 | testable int getAlignmentPatternPositions(int version, uint8_t result[7]); 70 | static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]); 71 | 72 | static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]); 73 | static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask); 74 | static long getPenaltyScore(const uint8_t qrcode[]); 75 | static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize); 76 | static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize); 77 | static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7]); 78 | 79 | testable bool getModule(const uint8_t qrcode[], int x, int y); 80 | testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack); 81 | testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack); 82 | static bool getBit(int x, int i); 83 | 84 | testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars); 85 | testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version); 86 | static int numCharCountBits(enum qrcodegen_Mode mode, int version); 87 | 88 | 89 | 90 | /*---- Private tables of constants ----*/ 91 | 92 | // The set of all legal characters in alphanumeric mode, where each character 93 | // value maps to the index in the string. For checking text and encoding segments. 94 | static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; 95 | 96 | // For generating error correction codes. 97 | testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = { 98 | // Version: (note that index 0 is for padding, and is set to an illegal value) 99 | //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level 100 | {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low 101 | {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium 102 | {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile 103 | {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High 104 | }; 105 | 106 | #define qrcodegen_REED_SOLOMON_DEGREE_MAX 30 // Based on the table above 107 | 108 | // For generating error correction codes. 109 | testable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = { 110 | // Version: (note that index 0 is for padding, and is set to an illegal value) 111 | //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level 112 | {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low 113 | {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium 114 | {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile 115 | {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High 116 | }; 117 | 118 | // For automatic mask pattern selection. 119 | static const int PENALTY_N1 = 3; 120 | static const int PENALTY_N2 = 3; 121 | static const int PENALTY_N3 = 40; 122 | static const int PENALTY_N4 = 10; 123 | 124 | 125 | 126 | /*---- High-level QR Code encoding functions ----*/ 127 | 128 | // Public function - see documentation comment in header file. 129 | bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], 130 | enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { 131 | 132 | size_t textLen = strlen(text); 133 | if (textLen == 0) 134 | return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); 135 | size_t bufLen = (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion); 136 | 137 | struct qrcodegen_Segment seg; 138 | if (qrcodegen_isNumeric(text)) { 139 | if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) 140 | goto fail; 141 | seg = qrcodegen_makeNumeric(text, tempBuffer); 142 | } else if (qrcodegen_isAlphanumeric(text)) { 143 | if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen) 144 | goto fail; 145 | seg = qrcodegen_makeAlphanumeric(text, tempBuffer); 146 | } else { 147 | if (textLen > bufLen) 148 | goto fail; 149 | for (size_t i = 0; i < textLen; i++) 150 | tempBuffer[i] = (uint8_t)text[i]; 151 | seg.mode = qrcodegen_Mode_BYTE; 152 | seg.bitLength = calcSegmentBitLength(seg.mode, textLen); 153 | if (seg.bitLength == -1) 154 | goto fail; 155 | seg.numChars = (int)textLen; 156 | seg.data = tempBuffer; 157 | } 158 | return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); 159 | 160 | fail: 161 | qrcode[0] = 0; // Set size to invalid value for safety 162 | return false; 163 | } 164 | 165 | 166 | // Public function - see documentation comment in header file. 167 | bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], 168 | enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { 169 | 170 | struct qrcodegen_Segment seg; 171 | seg.mode = qrcodegen_Mode_BYTE; 172 | seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); 173 | if (seg.bitLength == -1) { 174 | qrcode[0] = 0; // Set size to invalid value for safety 175 | return false; 176 | } 177 | seg.numChars = (int)dataLen; 178 | seg.data = dataAndTemp; 179 | return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, dataAndTemp, qrcode); 180 | } 181 | 182 | 183 | // Appends the given number of low-order bits of the given value to the given byte-based 184 | // bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits. 185 | testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen) { 186 | assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0); 187 | for (int i = numBits - 1; i >= 0; i--, (*bitLen)++) 188 | buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7)); 189 | } 190 | 191 | 192 | 193 | /*---- Low-level QR Code encoding functions ----*/ 194 | 195 | // Public function - see documentation comment in header file. 196 | bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, 197 | enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]) { 198 | return qrcodegen_encodeSegmentsAdvanced(segs, len, ecl, 199 | qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true, tempBuffer, qrcode); 200 | } 201 | 202 | 203 | // Public function - see documentation comment in header file. 204 | bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, 205 | int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]) { 206 | assert(segs != NULL || len == 0); 207 | assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX); 208 | assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7); 209 | 210 | // Find the minimal version number to use 211 | int version, dataUsedBits; 212 | for (version = minVersion; ; version++) { 213 | int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available 214 | dataUsedBits = getTotalBits(segs, len, version); 215 | if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) 216 | break; // This version number is found to be suitable 217 | if (version >= maxVersion) { // All versions in the range could not fit the given data 218 | qrcode[0] = 0; // Set size to invalid value for safety 219 | return false; 220 | } 221 | } 222 | assert(dataUsedBits != -1); 223 | 224 | // Increase the error correction level while the data still fits in the current version number 225 | for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { // From low to high 226 | if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8) 227 | ecl = (enum qrcodegen_Ecc)i; 228 | } 229 | 230 | // Concatenate all segments to create the data bit string 231 | memset(qrcode, 0, (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0])); 232 | int bitLen = 0; 233 | for (size_t i = 0; i < len; i++) { 234 | const struct qrcodegen_Segment *seg = &segs[i]; 235 | appendBitsToBuffer((unsigned int)seg->mode, 4, qrcode, &bitLen); 236 | appendBitsToBuffer((unsigned int)seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen); 237 | for (int j = 0; j < seg->bitLength; j++) { 238 | int bit = (seg->data[j >> 3] >> (7 - (j & 7))) & 1; 239 | appendBitsToBuffer((unsigned int)bit, 1, qrcode, &bitLen); 240 | } 241 | } 242 | assert(bitLen == dataUsedBits); 243 | 244 | // Add terminator and pad up to a byte if applicable 245 | int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; 246 | assert(bitLen <= dataCapacityBits); 247 | int terminatorBits = dataCapacityBits - bitLen; 248 | if (terminatorBits > 4) 249 | terminatorBits = 4; 250 | appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen); 251 | appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen); 252 | assert(bitLen % 8 == 0); 253 | 254 | // Pad with alternating bytes until data capacity is reached 255 | for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) 256 | appendBitsToBuffer(padByte, 8, qrcode, &bitLen); 257 | 258 | // Draw function and data codeword modules 259 | addEccAndInterleave(qrcode, version, ecl, tempBuffer); 260 | initializeFunctionModules(version, qrcode); 261 | drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode); 262 | drawWhiteFunctionModules(qrcode, version); 263 | initializeFunctionModules(version, tempBuffer); 264 | 265 | // Handle masking 266 | if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask 267 | long minPenalty = LONG_MAX; 268 | for (int i = 0; i < 8; i++) { 269 | enum qrcodegen_Mask msk = (enum qrcodegen_Mask)i; 270 | applyMask(tempBuffer, qrcode, msk); 271 | drawFormatBits(ecl, msk, qrcode); 272 | long penalty = getPenaltyScore(qrcode); 273 | if (penalty < minPenalty) { 274 | mask = msk; 275 | minPenalty = penalty; 276 | } 277 | applyMask(tempBuffer, qrcode, msk); // Undoes the mask due to XOR 278 | } 279 | } 280 | assert(0 <= (int)mask && (int)mask <= 7); 281 | applyMask(tempBuffer, qrcode, mask); 282 | drawFormatBits(ecl, mask, qrcode); 283 | return true; 284 | } 285 | 286 | 287 | 288 | /*---- Error correction code generation functions ----*/ 289 | 290 | // Appends error correction bytes to each block of the given data array, then interleaves 291 | // bytes from the blocks and stores them in the result array. data[0 : dataLen] contains 292 | // the input data. data[dataLen : rawCodewords] is used as a temporary work area and will 293 | // be clobbered by this function. The final answer is stored in result[0 : rawCodewords]. 294 | testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) { 295 | // Calculate parameter numbers 296 | assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); 297 | int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version]; 298 | int blockEccLen = ECC_CODEWORDS_PER_BLOCK [(int)ecl][version]; 299 | int rawCodewords = getNumRawDataModules(version) / 8; 300 | int dataLen = getNumDataCodewords(version, ecl); 301 | int numShortBlocks = numBlocks - rawCodewords % numBlocks; 302 | int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen; 303 | 304 | // Split data into blocks, calculate ECC, and interleave 305 | // (not concatenate) the bytes into a single sequence 306 | uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX]; 307 | reedSolomonComputeDivisor(blockEccLen, rsdiv); 308 | const uint8_t *dat = data; 309 | for (int i = 0; i < numBlocks; i++) { 310 | int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1); 311 | uint8_t *ecc = &data[dataLen]; // Temporary storage 312 | reedSolomonComputeRemainder(dat, datLen, rsdiv, blockEccLen, ecc); 313 | for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data 314 | if (j == shortBlockDataLen) 315 | k -= numShortBlocks; 316 | result[k] = dat[j]; 317 | } 318 | for (int j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks) // Copy ECC 319 | result[k] = ecc[j]; 320 | dat += datLen; 321 | } 322 | } 323 | 324 | 325 | // Returns the number of 8-bit codewords that can be used for storing data (not ECC), 326 | // for the given version number and error correction level. The result is in the range [9, 2956]. 327 | testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) { 328 | int v = version, e = (int)ecl; 329 | assert(0 <= e && e < 4); 330 | return getNumRawDataModules(v) / 8 331 | - ECC_CODEWORDS_PER_BLOCK [e][v] 332 | * NUM_ERROR_CORRECTION_BLOCKS[e][v]; 333 | } 334 | 335 | 336 | // Returns the number of data bits that can be stored in a QR Code of the given version number, after 337 | // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. 338 | // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. 339 | testable int getNumRawDataModules(int ver) { 340 | assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX); 341 | int result = (16 * ver + 128) * ver + 64; 342 | if (ver >= 2) { 343 | int numAlign = ver / 7 + 2; 344 | result -= (25 * numAlign - 10) * numAlign - 55; 345 | if (ver >= 7) 346 | result -= 36; 347 | } 348 | assert(208 <= result && result <= 29648); 349 | return result; 350 | } 351 | 352 | 353 | 354 | /*---- Reed-Solomon ECC generator functions ----*/ 355 | 356 | // Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree]. 357 | // This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm. 358 | testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) { 359 | assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); 360 | // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. 361 | // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. 362 | memset(result, 0, (size_t)degree * sizeof(result[0])); 363 | result[degree - 1] = 1; // Start off with the monomial x^0 364 | 365 | // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), 366 | // drop the highest monomial term which is always 1x^degree. 367 | // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). 368 | uint8_t root = 1; 369 | for (int i = 0; i < degree; i++) { 370 | // Multiply the current product by (x - r^i) 371 | for (int j = 0; j < degree; j++) { 372 | result[j] = reedSolomonMultiply(result[j], root); 373 | if (j + 1 < degree) 374 | result[j] ^= result[j + 1]; 375 | } 376 | root = reedSolomonMultiply(root, 0x02); 377 | } 378 | } 379 | 380 | 381 | // Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials. 382 | // The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree]. 383 | // All polynomials are in big endian, and the generator has an implicit leading 1 term. 384 | testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, 385 | const uint8_t generator[], int degree, uint8_t result[]) { 386 | assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); 387 | memset(result, 0, (size_t)degree * sizeof(result[0])); 388 | for (int i = 0; i < dataLen; i++) { // Polynomial division 389 | uint8_t factor = data[i] ^ result[0]; 390 | memmove(&result[0], &result[1], (size_t)(degree - 1) * sizeof(result[0])); 391 | result[degree - 1] = 0; 392 | for (int j = 0; j < degree; j++) 393 | result[j] ^= reedSolomonMultiply(generator[j], factor); 394 | } 395 | } 396 | 397 | #undef qrcodegen_REED_SOLOMON_DEGREE_MAX 398 | 399 | 400 | // Returns the product of the two given field elements modulo GF(2^8/0x11D). 401 | // All inputs are valid. This could be implemented as a 256*256 lookup table. 402 | testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y) { 403 | // Russian peasant multiplication 404 | uint8_t z = 0; 405 | for (int i = 7; i >= 0; i--) { 406 | z = (uint8_t)((z << 1) ^ ((z >> 7) * 0x11D)); 407 | z ^= ((y >> i) & 1) * x; 408 | } 409 | return z; 410 | } 411 | 412 | 413 | 414 | /*---- Drawing function modules ----*/ 415 | 416 | // Clears the given QR Code grid with white modules for the given 417 | // version's size, then marks every function module as black. 418 | testable void initializeFunctionModules(int version, uint8_t qrcode[]) { 419 | // Initialize QR Code 420 | int qrsize = version * 4 + 17; 421 | memset(qrcode, 0, (size_t)((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0])); 422 | qrcode[0] = (uint8_t)qrsize; 423 | 424 | // Fill horizontal and vertical timing patterns 425 | fillRectangle(6, 0, 1, qrsize, qrcode); 426 | fillRectangle(0, 6, qrsize, 1, qrcode); 427 | 428 | // Fill 3 finder patterns (all corners except bottom right) and format bits 429 | fillRectangle(0, 0, 9, 9, qrcode); 430 | fillRectangle(qrsize - 8, 0, 8, 9, qrcode); 431 | fillRectangle(0, qrsize - 8, 9, 8, qrcode); 432 | 433 | // Fill numerous alignment patterns 434 | uint8_t alignPatPos[7]; 435 | int numAlign = getAlignmentPatternPositions(version, alignPatPos); 436 | for (int i = 0; i < numAlign; i++) { 437 | for (int j = 0; j < numAlign; j++) { 438 | // Don't draw on the three finder corners 439 | if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) 440 | fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode); 441 | } 442 | } 443 | 444 | // Fill version blocks 445 | if (version >= 7) { 446 | fillRectangle(qrsize - 11, 0, 3, 6, qrcode); 447 | fillRectangle(0, qrsize - 11, 6, 3, qrcode); 448 | } 449 | } 450 | 451 | 452 | // Draws white function modules and possibly some black modules onto the given QR Code, without changing 453 | // non-function modules. This does not draw the format bits. This requires all function modules to be previously 454 | // marked black (namely by initializeFunctionModules()), because this may skip redrawing black function modules. 455 | static void drawWhiteFunctionModules(uint8_t qrcode[], int version) { 456 | // Draw horizontal and vertical timing patterns 457 | int qrsize = qrcodegen_getSize(qrcode); 458 | for (int i = 7; i < qrsize - 7; i += 2) { 459 | setModule(qrcode, 6, i, false); 460 | setModule(qrcode, i, 6, false); 461 | } 462 | 463 | // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) 464 | for (int dy = -4; dy <= 4; dy++) { 465 | for (int dx = -4; dx <= 4; dx++) { 466 | int dist = abs(dx); 467 | if (abs(dy) > dist) 468 | dist = abs(dy); 469 | if (dist == 2 || dist == 4) { 470 | setModuleBounded(qrcode, 3 + dx, 3 + dy, false); 471 | setModuleBounded(qrcode, qrsize - 4 + dx, 3 + dy, false); 472 | setModuleBounded(qrcode, 3 + dx, qrsize - 4 + dy, false); 473 | } 474 | } 475 | } 476 | 477 | // Draw numerous alignment patterns 478 | uint8_t alignPatPos[7]; 479 | int numAlign = getAlignmentPatternPositions(version, alignPatPos); 480 | for (int i = 0; i < numAlign; i++) { 481 | for (int j = 0; j < numAlign; j++) { 482 | if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)) 483 | continue; // Don't draw on the three finder corners 484 | for (int dy = -1; dy <= 1; dy++) { 485 | for (int dx = -1; dx <= 1; dx++) 486 | setModule(qrcode, alignPatPos[i] + dx, alignPatPos[j] + dy, dx == 0 && dy == 0); 487 | } 488 | } 489 | } 490 | 491 | // Draw version blocks 492 | if (version >= 7) { 493 | // Calculate error correction code and pack bits 494 | int rem = version; // version is uint6, in the range [7, 40] 495 | for (int i = 0; i < 12; i++) 496 | rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); 497 | long bits = (long)version << 12 | rem; // uint18 498 | assert(bits >> 18 == 0); 499 | 500 | // Draw two copies 501 | for (int i = 0; i < 6; i++) { 502 | for (int j = 0; j < 3; j++) { 503 | int k = qrsize - 11 + j; 504 | setModule(qrcode, k, i, (bits & 1) != 0); 505 | setModule(qrcode, i, k, (bits & 1) != 0); 506 | bits >>= 1; 507 | } 508 | } 509 | } 510 | } 511 | 512 | 513 | // Draws two copies of the format bits (with its own error correction code) based 514 | // on the given mask and error correction level. This always draws all modules of 515 | // the format bits, unlike drawWhiteFunctionModules() which might skip black modules. 516 | static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) { 517 | // Calculate error correction code and pack bits 518 | assert(0 <= (int)mask && (int)mask <= 7); 519 | static const int table[] = {1, 0, 3, 2}; 520 | int data = table[(int)ecl] << 3 | (int)mask; // errCorrLvl is uint2, mask is uint3 521 | int rem = data; 522 | for (int i = 0; i < 10; i++) 523 | rem = (rem << 1) ^ ((rem >> 9) * 0x537); 524 | int bits = (data << 10 | rem) ^ 0x5412; // uint15 525 | assert(bits >> 15 == 0); 526 | 527 | // Draw first copy 528 | for (int i = 0; i <= 5; i++) 529 | setModule(qrcode, 8, i, getBit(bits, i)); 530 | setModule(qrcode, 8, 7, getBit(bits, 6)); 531 | setModule(qrcode, 8, 8, getBit(bits, 7)); 532 | setModule(qrcode, 7, 8, getBit(bits, 8)); 533 | for (int i = 9; i < 15; i++) 534 | setModule(qrcode, 14 - i, 8, getBit(bits, i)); 535 | 536 | // Draw second copy 537 | int qrsize = qrcodegen_getSize(qrcode); 538 | for (int i = 0; i < 8; i++) 539 | setModule(qrcode, qrsize - 1 - i, 8, getBit(bits, i)); 540 | for (int i = 8; i < 15; i++) 541 | setModule(qrcode, 8, qrsize - 15 + i, getBit(bits, i)); 542 | setModule(qrcode, 8, qrsize - 8, true); // Always black 543 | } 544 | 545 | 546 | // Calculates and stores an ascending list of positions of alignment patterns 547 | // for this version number, returning the length of the list (in the range [0,7]). 548 | // Each position is in the range [0,177), and are used on both the x and y axes. 549 | // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. 550 | testable int getAlignmentPatternPositions(int version, uint8_t result[7]) { 551 | if (version == 1) 552 | return 0; 553 | int numAlign = version / 7 + 2; 554 | int step = (version == 32) ? 26 : 555 | (version*4 + numAlign*2 + 1) / (numAlign*2 - 2) * 2; 556 | for (int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) 557 | result[i] = (uint8_t)pos; 558 | result[0] = 6; 559 | return numAlign; 560 | } 561 | 562 | 563 | // Sets every pixel in the range [left : left + width] * [top : top + height] to black. 564 | static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]) { 565 | for (int dy = 0; dy < height; dy++) { 566 | for (int dx = 0; dx < width; dx++) 567 | setModule(qrcode, left + dx, top + dy, true); 568 | } 569 | } 570 | 571 | 572 | 573 | /*---- Drawing data modules and masking ----*/ 574 | 575 | // Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of 576 | // the QR Code to be black at function modules and white at codeword modules (including unused remainder bits). 577 | static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) { 578 | int qrsize = qrcodegen_getSize(qrcode); 579 | int i = 0; // Bit index into the data 580 | // Do the funny zigzag scan 581 | for (int right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair 582 | if (right == 6) 583 | right = 5; 584 | for (int vert = 0; vert < qrsize; vert++) { // Vertical counter 585 | for (int j = 0; j < 2; j++) { 586 | int x = right - j; // Actual x coordinate 587 | bool upward = ((right + 1) & 2) == 0; 588 | int y = upward ? qrsize - 1 - vert : vert; // Actual y coordinate 589 | if (!getModule(qrcode, x, y) && i < dataLen * 8) { 590 | bool black = getBit(data[i >> 3], 7 - (i & 7)); 591 | setModule(qrcode, x, y, black); 592 | i++; 593 | } 594 | // If this QR Code has any remainder bits (0 to 7), they were assigned as 595 | // 0/false/white by the constructor and are left unchanged by this method 596 | } 597 | } 598 | } 599 | assert(i == dataLen * 8); 600 | } 601 | 602 | 603 | // XORs the codeword modules in this QR Code with the given mask pattern. 604 | // The function modules must be marked and the codeword bits must be drawn 605 | // before masking. Due to the arithmetic of XOR, calling applyMask() with 606 | // the same mask value a second time will undo the mask. A final well-formed 607 | // QR Code needs exactly one (not zero, two, etc.) mask applied. 608 | static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask) { 609 | assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO 610 | int qrsize = qrcodegen_getSize(qrcode); 611 | for (int y = 0; y < qrsize; y++) { 612 | for (int x = 0; x < qrsize; x++) { 613 | if (getModule(functionModules, x, y)) 614 | continue; 615 | bool invert; 616 | switch ((int)mask) { 617 | case 0: invert = (x + y) % 2 == 0; break; 618 | case 1: invert = y % 2 == 0; break; 619 | case 2: invert = x % 3 == 0; break; 620 | case 3: invert = (x + y) % 3 == 0; break; 621 | case 4: invert = (x / 3 + y / 2) % 2 == 0; break; 622 | case 5: invert = x * y % 2 + x * y % 3 == 0; break; 623 | case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break; 624 | case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break; 625 | default: assert(false); return; 626 | } 627 | bool val = getModule(qrcode, x, y); 628 | setModule(qrcode, x, y, val ^ invert); 629 | } 630 | } 631 | } 632 | 633 | 634 | // Calculates and returns the penalty score based on state of the given QR Code's current modules. 635 | // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. 636 | static long getPenaltyScore(const uint8_t qrcode[]) { 637 | int qrsize = qrcodegen_getSize(qrcode); 638 | long result = 0; 639 | 640 | // Adjacent modules in row having same color, and finder-like patterns 641 | for (int y = 0; y < qrsize; y++) { 642 | bool runColor = false; 643 | int runX = 0; 644 | int runHistory[7] = {0}; 645 | int padRun = qrsize; // Add white border to initial run 646 | for (int x = 0; x < qrsize; x++) { 647 | if (getModule(qrcode, x, y) == runColor) { 648 | runX++; 649 | if (runX == 5) 650 | result += PENALTY_N1; 651 | else if (runX > 5) 652 | result++; 653 | } else { 654 | finderPenaltyAddHistory(runX + padRun, runHistory); 655 | padRun = 0; 656 | if (!runColor) 657 | result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; 658 | runColor = getModule(qrcode, x, y); 659 | runX = 1; 660 | } 661 | } 662 | result += finderPenaltyTerminateAndCount(runColor, runX + padRun, runHistory, qrsize) * PENALTY_N3; 663 | } 664 | // Adjacent modules in column having same color, and finder-like patterns 665 | for (int x = 0; x < qrsize; x++) { 666 | bool runColor = false; 667 | int runY = 0; 668 | int runHistory[7] = {0}; 669 | int padRun = qrsize; // Add white border to initial run 670 | for (int y = 0; y < qrsize; y++) { 671 | if (getModule(qrcode, x, y) == runColor) { 672 | runY++; 673 | if (runY == 5) 674 | result += PENALTY_N1; 675 | else if (runY > 5) 676 | result++; 677 | } else { 678 | finderPenaltyAddHistory(runY + padRun, runHistory); 679 | padRun = 0; 680 | if (!runColor) 681 | result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; 682 | runColor = getModule(qrcode, x, y); 683 | runY = 1; 684 | } 685 | } 686 | result += finderPenaltyTerminateAndCount(runColor, runY + padRun, runHistory, qrsize) * PENALTY_N3; 687 | } 688 | 689 | // 2*2 blocks of modules having same color 690 | for (int y = 0; y < qrsize - 1; y++) { 691 | for (int x = 0; x < qrsize - 1; x++) { 692 | bool color = getModule(qrcode, x, y); 693 | if ( color == getModule(qrcode, x + 1, y) && 694 | color == getModule(qrcode, x, y + 1) && 695 | color == getModule(qrcode, x + 1, y + 1)) 696 | result += PENALTY_N2; 697 | } 698 | } 699 | 700 | // Balance of black and white modules 701 | int black = 0; 702 | for (int y = 0; y < qrsize; y++) { 703 | for (int x = 0; x < qrsize; x++) { 704 | if (getModule(qrcode, x, y)) 705 | black++; 706 | } 707 | } 708 | int total = qrsize * qrsize; // Note that size is odd, so black/total != 1/2 709 | // Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)% 710 | int k = (int)((labs(black * 20L - total * 10L) + total - 1) / total) - 1; 711 | result += k * PENALTY_N4; 712 | return result; 713 | } 714 | 715 | 716 | // Can only be called immediately after a white run is added, and 717 | // returns either 0, 1, or 2. A helper function for getPenaltyScore(). 718 | static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize) { 719 | int n = runHistory[1]; 720 | assert(n <= qrsize * 3); 721 | bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n; 722 | // The maximum QR Code size is 177, hence the black run length n <= 177. 723 | // Arithmetic is promoted to int, so n*4 will not overflow. 724 | return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) 725 | + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); 726 | } 727 | 728 | 729 | // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). 730 | static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize) { 731 | if (currentRunColor) { // Terminate black run 732 | finderPenaltyAddHistory(currentRunLength, runHistory); 733 | currentRunLength = 0; 734 | } 735 | currentRunLength += qrsize; // Add white border to final run 736 | finderPenaltyAddHistory(currentRunLength, runHistory); 737 | return finderPenaltyCountPatterns(runHistory, qrsize); 738 | } 739 | 740 | 741 | // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). 742 | static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7]) { 743 | memmove(&runHistory[1], &runHistory[0], 6 * sizeof(runHistory[0])); 744 | runHistory[0] = currentRunLength; 745 | } 746 | 747 | 748 | 749 | /*---- Basic QR Code information ----*/ 750 | 751 | // Public function - see documentation comment in header file. 752 | int qrcodegen_getSize(const uint8_t qrcode[]) { 753 | assert(qrcode != NULL); 754 | int result = qrcode[0]; 755 | assert((qrcodegen_VERSION_MIN * 4 + 17) <= result 756 | && result <= (qrcodegen_VERSION_MAX * 4 + 17)); 757 | return result; 758 | } 759 | 760 | 761 | // Public function - see documentation comment in header file. 762 | bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) { 763 | assert(qrcode != NULL); 764 | int qrsize = qrcode[0]; 765 | return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModule(qrcode, x, y); 766 | } 767 | 768 | 769 | // Gets the module at the given coordinates, which must be in bounds. 770 | testable bool getModule(const uint8_t qrcode[], int x, int y) { 771 | int qrsize = qrcode[0]; 772 | assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); 773 | int index = y * qrsize + x; 774 | return getBit(qrcode[(index >> 3) + 1], index & 7); 775 | } 776 | 777 | 778 | // Sets the module at the given coordinates, which must be in bounds. 779 | testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack) { 780 | int qrsize = qrcode[0]; 781 | assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); 782 | int index = y * qrsize + x; 783 | int bitIndex = index & 7; 784 | int byteIndex = (index >> 3) + 1; 785 | if (isBlack) 786 | qrcode[byteIndex] |= 1 << bitIndex; 787 | else 788 | qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF; 789 | } 790 | 791 | 792 | // Sets the module at the given coordinates, doing nothing if out of bounds. 793 | testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack) { 794 | int qrsize = qrcode[0]; 795 | if (0 <= x && x < qrsize && 0 <= y && y < qrsize) 796 | setModule(qrcode, x, y, isBlack); 797 | } 798 | 799 | 800 | // Returns true iff the i'th bit of x is set to 1. Requires x >= 0 and 0 <= i <= 14. 801 | static bool getBit(int x, int i) { 802 | return ((x >> i) & 1) != 0; 803 | } 804 | 805 | 806 | 807 | /*---- Segment handling ----*/ 808 | 809 | // Public function - see documentation comment in header file. 810 | bool qrcodegen_isAlphanumeric(const char *text) { 811 | assert(text != NULL); 812 | for (; *text != '\0'; text++) { 813 | if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) 814 | return false; 815 | } 816 | return true; 817 | } 818 | 819 | 820 | // Public function - see documentation comment in header file. 821 | bool qrcodegen_isNumeric(const char *text) { 822 | assert(text != NULL); 823 | for (; *text != '\0'; text++) { 824 | if (*text < '0' || *text > '9') 825 | return false; 826 | } 827 | return true; 828 | } 829 | 830 | 831 | // Public function - see documentation comment in header file. 832 | size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars) { 833 | int temp = calcSegmentBitLength(mode, numChars); 834 | if (temp == -1) 835 | return SIZE_MAX; 836 | assert(0 <= temp && temp <= INT16_MAX); 837 | return ((size_t)temp + 7) / 8; 838 | } 839 | 840 | 841 | // Returns the number of data bits needed to represent a segment 842 | // containing the given number of characters using the given mode. Notes: 843 | // - Returns -1 on failure, i.e. numChars > INT16_MAX or 844 | // the number of needed bits exceeds INT16_MAX (i.e. 32767). 845 | // - Otherwise, all valid results are in the range [0, INT16_MAX]. 846 | // - For byte mode, numChars measures the number of bytes, not Unicode code points. 847 | // - For ECI mode, numChars must be 0, and the worst-case number of bits is returned. 848 | // An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. 849 | testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { 850 | // All calculations are designed to avoid overflow on all platforms 851 | if (numChars > (unsigned int)INT16_MAX) 852 | return -1; 853 | long result = (long)numChars; 854 | if (mode == qrcodegen_Mode_NUMERIC) 855 | result = (result * 10 + 2) / 3; // ceil(10/3 * n) 856 | else if (mode == qrcodegen_Mode_ALPHANUMERIC) 857 | result = (result * 11 + 1) / 2; // ceil(11/2 * n) 858 | else if (mode == qrcodegen_Mode_BYTE) 859 | result *= 8; 860 | else if (mode == qrcodegen_Mode_KANJI) 861 | result *= 13; 862 | else if (mode == qrcodegen_Mode_ECI && numChars == 0) 863 | result = 3 * 8; 864 | else { // Invalid argument 865 | assert(false); 866 | return -1; 867 | } 868 | assert(result >= 0); 869 | if (result > INT16_MAX) 870 | return -1; 871 | return (int)result; 872 | } 873 | 874 | 875 | // Public function - see documentation comment in header file. 876 | struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]) { 877 | assert(data != NULL || len == 0); 878 | struct qrcodegen_Segment result; 879 | result.mode = qrcodegen_Mode_BYTE; 880 | result.bitLength = calcSegmentBitLength(result.mode, len); 881 | assert(result.bitLength != -1); 882 | result.numChars = (int)len; 883 | if (len > 0) 884 | memcpy(buf, data, len * sizeof(buf[0])); 885 | result.data = buf; 886 | return result; 887 | } 888 | 889 | 890 | // Public function - see documentation comment in header file. 891 | struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) { 892 | assert(digits != NULL); 893 | struct qrcodegen_Segment result; 894 | size_t len = strlen(digits); 895 | result.mode = qrcodegen_Mode_NUMERIC; 896 | int bitLen = calcSegmentBitLength(result.mode, len); 897 | assert(bitLen != -1); 898 | result.numChars = (int)len; 899 | if (bitLen > 0) 900 | memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); 901 | result.bitLength = 0; 902 | 903 | unsigned int accumData = 0; 904 | int accumCount = 0; 905 | for (; *digits != '\0'; digits++) { 906 | char c = *digits; 907 | assert('0' <= c && c <= '9'); 908 | accumData = accumData * 10 + (unsigned int)(c - '0'); 909 | accumCount++; 910 | if (accumCount == 3) { 911 | appendBitsToBuffer(accumData, 10, buf, &result.bitLength); 912 | accumData = 0; 913 | accumCount = 0; 914 | } 915 | } 916 | if (accumCount > 0) // 1 or 2 digits remaining 917 | appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength); 918 | assert(result.bitLength == bitLen); 919 | result.data = buf; 920 | return result; 921 | } 922 | 923 | 924 | // Public function - see documentation comment in header file. 925 | struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) { 926 | assert(text != NULL); 927 | struct qrcodegen_Segment result; 928 | size_t len = strlen(text); 929 | result.mode = qrcodegen_Mode_ALPHANUMERIC; 930 | int bitLen = calcSegmentBitLength(result.mode, len); 931 | assert(bitLen != -1); 932 | result.numChars = (int)len; 933 | if (bitLen > 0) 934 | memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); 935 | result.bitLength = 0; 936 | 937 | unsigned int accumData = 0; 938 | int accumCount = 0; 939 | for (; *text != '\0'; text++) { 940 | const char *temp = strchr(ALPHANUMERIC_CHARSET, *text); 941 | assert(temp != NULL); 942 | accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET); 943 | accumCount++; 944 | if (accumCount == 2) { 945 | appendBitsToBuffer(accumData, 11, buf, &result.bitLength); 946 | accumData = 0; 947 | accumCount = 0; 948 | } 949 | } 950 | if (accumCount > 0) // 1 character remaining 951 | appendBitsToBuffer(accumData, 6, buf, &result.bitLength); 952 | assert(result.bitLength == bitLen); 953 | result.data = buf; 954 | return result; 955 | } 956 | 957 | 958 | // Public function - see documentation comment in header file. 959 | struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) { 960 | struct qrcodegen_Segment result; 961 | result.mode = qrcodegen_Mode_ECI; 962 | result.numChars = 0; 963 | result.bitLength = 0; 964 | if (assignVal < 0) 965 | assert(false); 966 | else if (assignVal < (1 << 7)) { 967 | memset(buf, 0, 1 * sizeof(buf[0])); 968 | appendBitsToBuffer((unsigned int)assignVal, 8, buf, &result.bitLength); 969 | } else if (assignVal < (1 << 14)) { 970 | memset(buf, 0, 2 * sizeof(buf[0])); 971 | appendBitsToBuffer(2, 2, buf, &result.bitLength); 972 | appendBitsToBuffer((unsigned int)assignVal, 14, buf, &result.bitLength); 973 | } else if (assignVal < 1000000L) { 974 | memset(buf, 0, 3 * sizeof(buf[0])); 975 | appendBitsToBuffer(6, 3, buf, &result.bitLength); 976 | appendBitsToBuffer((unsigned int)(assignVal >> 10), 11, buf, &result.bitLength); 977 | appendBitsToBuffer((unsigned int)(assignVal & 0x3FF), 10, buf, &result.bitLength); 978 | } else 979 | assert(false); 980 | result.data = buf; 981 | return result; 982 | } 983 | 984 | 985 | // Calculates the number of bits needed to encode the given segments at the given version. 986 | // Returns a non-negative number if successful. Otherwise returns -1 if a segment has too 987 | // many characters to fit its length field, or the total bits exceeds INT16_MAX. 988 | testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) { 989 | assert(segs != NULL || len == 0); 990 | long result = 0; 991 | for (size_t i = 0; i < len; i++) { 992 | int numChars = segs[i].numChars; 993 | int bitLength = segs[i].bitLength; 994 | assert(0 <= numChars && numChars <= INT16_MAX); 995 | assert(0 <= bitLength && bitLength <= INT16_MAX); 996 | int ccbits = numCharCountBits(segs[i].mode, version); 997 | assert(0 <= ccbits && ccbits <= 16); 998 | if (numChars >= (1L << ccbits)) 999 | return -1; // The segment's length doesn't fit the field's bit width 1000 | result += 4L + ccbits + bitLength; 1001 | if (result > INT16_MAX) 1002 | return -1; // The sum might overflow an int type 1003 | } 1004 | assert(0 <= result && result <= INT16_MAX); 1005 | return (int)result; 1006 | } 1007 | 1008 | 1009 | // Returns the bit width of the character count field for a segment in the given mode 1010 | // in a QR Code at the given version number. The result is in the range [0, 16]. 1011 | static int numCharCountBits(enum qrcodegen_Mode mode, int version) { 1012 | assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); 1013 | int i = (version + 7) / 17; 1014 | switch (mode) { 1015 | case qrcodegen_Mode_NUMERIC : { static const int temp[] = {10, 12, 14}; return temp[i]; } 1016 | case qrcodegen_Mode_ALPHANUMERIC: { static const int temp[] = { 9, 11, 13}; return temp[i]; } 1017 | case qrcodegen_Mode_BYTE : { static const int temp[] = { 8, 16, 16}; return temp[i]; } 1018 | case qrcodegen_Mode_KANJI : { static const int temp[] = { 8, 10, 12}; return temp[i]; } 1019 | case qrcodegen_Mode_ECI : return 0; 1020 | default: assert(false); return -1; // Dummy value 1021 | } 1022 | } 1023 | --------------------------------------------------------------------------------