├── .gitignore ├── LICENSE.md ├── README.md ├── examples ├── basic │ └── basic.ino └── wifi_http_webhook │ └── wifi_http_webhook.ino ├── include ├── ESP32CameraPins.h └── ESP32QRCodeReader.h ├── library.json ├── library.properties ├── pio └── platformio.ini └── src ├── ESP32QRCodeReader.cpp ├── openmv ├── collections.c ├── collections.h └── fmath.h └── quirc ├── LICENSE ├── README.md ├── decode.c ├── identify.c ├── quirc.c ├── quirc.h ├── quirc_internal.h └── version_db.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lo 3 | .DS_Store 4 | *.tar.gz -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Alvaro Viebrantz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32 QR Code Reader 2 | 3 | This library provides a interface to read QR Codes using an ESP32 with a camera. 4 | 5 | Internally this lib uses a slight modified version of the [Quirc library](https://github.com/dlbeer/quirc) and some code from OpenMV port on the [MaixPy](https://github.com/sipeed/MaixPy) project. 6 | 7 | ## Demos 8 | 9 | - EN-US - See demo video at https://twitter.com/alvaroviebrantz/status/1290116219199279104?s=20 10 | - PT-BR - Veja video de demo em https://twitter.com/alvaroviebrantz/status/1290116405824806912?s=20 11 | 12 | ## Usage 13 | 14 | Is recommended to use PlatformIO to install this lib. Add `ESP32QRCodeReader` to your `platformio.ini` file. 15 | 16 | From PlatformIO library: 17 | 18 | ``` 19 | lib_deps= 20 | ESP32QRCodeReader 21 | ``` 22 | 23 | Directly from Github: 24 | 25 | ``` 26 | lib_deps = 27 | alvarowolfx/ESP32QRCodeReader 28 | ``` 29 | 30 | ## Examples 31 | 32 | This library comes with a number of example sketches. See File > Examples > ESP32QRCodeReader 33 | within the Arduino application. You can see them on the `examples` folder on this repository. 34 | 35 | Basic example: 36 | 37 | ``` 38 | #include 39 | 40 | // See available models on README.md or ESP32CameraPins.h 41 | ESP32QRCodeReader reader(CAMERA_MODEL_AI_THINKER); 42 | 43 | void onQrCodeTask(void *pvParameters) 44 | { 45 | struct QRCodeData qrCodeData; 46 | 47 | while (true) 48 | { 49 | if (reader.receiveQrCode(&qrCodeData, 100)) 50 | { 51 | Serial.println("Found QRCode"); 52 | if (qrCodeData.valid) 53 | { 54 | Serial.print("Payload: "); 55 | Serial.println((const char *)qrCodeData.payload); 56 | } 57 | else 58 | { 59 | Serial.print("Invalid: "); 60 | Serial.println((const char *)qrCodeData.payload); 61 | } 62 | } 63 | vTaskDelay(100 / portTICK_PERIOD_MS); 64 | } 65 | } 66 | 67 | void setup() 68 | { 69 | Serial.begin(115200); 70 | Serial.println(); 71 | 72 | reader.setup(); 73 | reader.beginOnCore(1); 74 | xTaskCreate(onQrCodeTask, "onQrCode", 4 * 1024, NULL, 4, NULL); 75 | } 76 | ``` 77 | 78 | ## Limitations 79 | 80 | - Need an ESP32 module with PSRAM - See below. 81 | 82 | ## Compatible Hardware 83 | 84 | The QR Code recognition lib required a lot of memory, so I was only able to get this to work with an ESP32 that has PSRRAM available and also the Quirc library is modified to use that directly. 85 | 86 | - [ESP32](https://espressif.com/en/products/hardware/esp32/overview) module 87 | - PSRAM Available 88 | - Camera module - Tested with OV2640 89 | 90 | ESP32 modules with camera that have PSRAM and should work: 91 | 92 | - CAMERA_MODEL_WROVER_KIT 93 | - CAMERA_MODEL_ESP_EYE 94 | - CAMERA_MODEL_M5STACK_PSRAM 95 | - CAMERA_MODEL_M5STACK_V2_PSRAM 96 | - CAMERA_MODEL_M5STACK_WIDE 97 | - CAMERA_MODEL_AI_THINKER 98 | 99 | ESP32 modules without PSRAM that will not work: 100 | 101 | - CAMERA_MODEL_M5STACK_ESP32CAM 102 | - CAMERA_MODEL_TTGO_T_JOURNAL 103 | 104 | ## License 105 | 106 | This code is released under the MIT License. 107 | 108 | ### References 109 | 110 | - https://github.com/dlbeer/quirc 111 | - https://github.com/sipeed/MaixPy 112 | - https://github.com/Schaggo/QR-ARDUINO 113 | - https://github.com/donny681/ESP32_CAMERA_QR 114 | -------------------------------------------------------------------------------- /examples/basic/basic.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | ESP32QRCodeReader reader(CAMERA_MODEL_AI_THINKER); 5 | 6 | void onQrCodeTask(void *pvParameters) 7 | { 8 | struct QRCodeData qrCodeData; 9 | 10 | while (true) 11 | { 12 | if (reader.receiveQrCode(&qrCodeData, 100)) 13 | { 14 | Serial.println("Found QRCode"); 15 | if (qrCodeData.valid) 16 | { 17 | Serial.print("Payload: "); 18 | Serial.println((const char *)qrCodeData.payload); 19 | } 20 | else 21 | { 22 | Serial.print("Invalid: "); 23 | Serial.println((const char *)qrCodeData.payload); 24 | } 25 | } 26 | vTaskDelay(100 / portTICK_PERIOD_MS); 27 | } 28 | } 29 | 30 | void setup() 31 | { 32 | Serial.begin(115200); 33 | Serial.println(); 34 | 35 | reader.setup(); 36 | 37 | Serial.println("Setup QRCode Reader"); 38 | 39 | reader.beginOnCore(1); 40 | 41 | Serial.println("Begin on Core 1"); 42 | 43 | xTaskCreate(onQrCodeTask, "onQrCode", 4 * 1024, NULL, 4, NULL); 44 | } 45 | 46 | void loop() 47 | { 48 | delay(100); 49 | } -------------------------------------------------------------------------------- /examples/wifi_http_webhook/wifi_http_webhook.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define WIFI_SSID "YOUR_SSID" 7 | #define WIFI_PASSWORD "YOUR_PASSWORD" 8 | #define WEBHOOK_URL "https//your-url:8080/endpoint" 9 | #define DOOR_RELAY_PIN 12 10 | 11 | ESP32QRCodeReader reader(CAMERA_MODEL_AI_THINKER); 12 | struct QRCodeData qrCodeData; 13 | bool isConnected = false; 14 | 15 | void openDoor() 16 | { 17 | digitalWrite(DOOR_RELAY_PIN, LOW); 18 | } 19 | 20 | void closeDoor() 21 | { 22 | digitalWrite(DOOR_RELAY_PIN, HIGH); 23 | } 24 | 25 | bool connectWifi() 26 | { 27 | if (WiFi.status() == WL_CONNECTED) 28 | { 29 | return true; 30 | } 31 | 32 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 33 | int maxRetries = 10; 34 | while (WiFi.status() != WL_CONNECTED) 35 | { 36 | delay(500); 37 | Serial.print("."); 38 | maxRetries--; 39 | if (maxRetries <= 0) 40 | { 41 | return false; 42 | } 43 | } 44 | Serial.println(""); 45 | Serial.println("WiFi connected"); 46 | return true; 47 | } 48 | 49 | void callWebhook(String code) 50 | { 51 | HTTPClient http; 52 | http.begin(String(WEBHOOK_URL) + "?code=" + code); 53 | 54 | int httpCode = http.GET(); 55 | if (httpCode == HTTP_CODE_OK) 56 | { 57 | Serial.println("Open door"); 58 | openDoor(); 59 | delay(2000); 60 | closeDoor(); 61 | } 62 | else 63 | { 64 | Serial.println("Not authorized"); 65 | closeDoor(); 66 | } 67 | 68 | http.end(); 69 | } 70 | void setup() 71 | { 72 | Serial.begin(115200); 73 | Serial.println(); 74 | 75 | pinMode(DOOR_RELAY_PIN, OUTPUT); 76 | closeDoor(); 77 | 78 | reader.setup(); 79 | //reader.setDebug(true); 80 | Serial.println("Setup QRCode Reader"); 81 | 82 | reader.begin(); 83 | Serial.println("Begin QR Code reader"); 84 | 85 | delay(1000); 86 | } 87 | 88 | void loop() 89 | { 90 | bool connected = connectWifi(); 91 | if (isConnected != connected) 92 | { 93 | isConnected = connected; 94 | } 95 | if (reader.receiveQrCode(&qrCodeData, 100)) 96 | { 97 | Serial.println("Found QRCode"); 98 | if (qrCodeData.valid) 99 | { 100 | Serial.print("Payload: "); 101 | Serial.println((const char *)qrCodeData.payload); 102 | callWebhook(String((const char *)qrCodeData.payload)); 103 | } 104 | else 105 | { 106 | Serial.print("Invalid: "); 107 | Serial.println((const char *)qrCodeData.payload); 108 | } 109 | } 110 | delay(300); 111 | } -------------------------------------------------------------------------------- /include/ESP32CameraPins.h: -------------------------------------------------------------------------------- 1 | #ifndef ESP32_CAMERA_PINS_H_ 2 | #define ESP32_CAMERA_PINS_H_ 3 | 4 | struct CameraPins 5 | { 6 | int PWDN_GPIO_NUM; 7 | int RESET_GPIO_NUM; 8 | int XCLK_GPIO_NUM; 9 | int SIOD_GPIO_NUM; 10 | int SIOC_GPIO_NUM; 11 | int Y9_GPIO_NUM; 12 | int Y8_GPIO_NUM; 13 | int Y7_GPIO_NUM; 14 | int Y6_GPIO_NUM; 15 | int Y5_GPIO_NUM; 16 | int Y4_GPIO_NUM; 17 | int Y3_GPIO_NUM; 18 | int Y2_GPIO_NUM; 19 | int VSYNC_GPIO_NUM; 20 | int HREF_GPIO_NUM; 21 | int PCLK_GPIO_NUM; 22 | }; 23 | 24 | #define CAMERA_MODEL_WROVER_KIT \ 25 | { \ 26 | .PWDN_GPIO_NUM = -1, \ 27 | .RESET_GPIO_NUM = -1, \ 28 | .XCLK_GPIO_NUM = 21, \ 29 | .SIOD_GPIO_NUM = 26, \ 30 | .SIOC_GPIO_NUM = 27, \ 31 | .Y9_GPIO_NUM = 35, \ 32 | .Y8_GPIO_NUM = 34, \ 33 | .Y7_GPIO_NUM = 39, \ 34 | .Y6_GPIO_NUM = 36, \ 35 | .Y5_GPIO_NUM = 19, \ 36 | .Y4_GPIO_NUM = 18, \ 37 | .Y3_GPIO_NUM = 5, \ 38 | .Y2_GPIO_NUM = 4, \ 39 | .VSYNC_GPIO_NUM = 25, \ 40 | .HREF_GPIO_NUM = 23, \ 41 | .PCLK_GPIO_NUM = 22, \ 42 | } 43 | 44 | #define CAMERA_MODEL_ESP_EYE \ 45 | { \ 46 | .PWDN_GPIO_NUM = -1, \ 47 | .RESET_GPIO_NUM = -1, \ 48 | .XCLK_GPIO_NUM = 4, \ 49 | .SIOD_GPIO_NUM = 18, \ 50 | .SIOC_GPIO_NUM = 23, \ 51 | .Y9_GPIO_NUM = 36, \ 52 | .Y8_GPIO_NUM = 37, \ 53 | .Y7_GPIO_NUM = 38, \ 54 | .Y6_GPIO_NUM = 39, \ 55 | .Y5_GPIO_NUM = 35, \ 56 | .Y4_GPIO_NUM = 14, \ 57 | .Y3_GPIO_NUM = 13, \ 58 | .Y2_GPIO_NUM = 34, \ 59 | .VSYNC_GPIO_NUM = 5, \ 60 | .HREF_GPIO_NUM = 27, \ 61 | .PCLK_GPIO_NUM = 25, \ 62 | } 63 | 64 | #define CAMERA_MODEL_M5STACK_PSRAM \ 65 | { \ 66 | .PWDN_GPIO_NUM = -1, \ 67 | .RESET_GPIO_NUM = 15, \ 68 | .XCLK_GPIO_NUM = 27, \ 69 | .SIOD_GPIO_NUM = 25, \ 70 | .SIOC_GPIO_NUM = 23, \ 71 | .Y9_GPIO_NUM = 19, \ 72 | .Y8_GPIO_NUM = 36, \ 73 | .Y7_GPIO_NUM = 18, \ 74 | .Y6_GPIO_NUM = 39, \ 75 | .Y5_GPIO_NUM = 5, \ 76 | .Y4_GPIO_NUM = 34, \ 77 | .Y3_GPIO_NUM = 35, \ 78 | .Y2_GPIO_NUM = 32, \ 79 | .VSYNC_GPIO_NUM = 22, \ 80 | .HREF_GPIO_NUM = 26, \ 81 | .PCLK_GPIO_NUM = 21, \ 82 | } 83 | 84 | #define CAMERA_MODEL_M5STACK_V2_PSRAM \ 85 | { \ 86 | .PWDN_GPIO_NUM = -1, \ 87 | .RESET_GPIO_NUM = 15, \ 88 | .XCLK_GPIO_NUM = 27, \ 89 | .SIOD_GPIO_NUM = 22, \ 90 | .SIOC_GPIO_NUM = 23, \ 91 | .Y9_GPIO_NUM = 19, \ 92 | .Y8_GPIO_NUM = 36, \ 93 | .Y7_GPIO_NUM = 18, \ 94 | .Y6_GPIO_NUM = 39, \ 95 | .Y5_GPIO_NUM = 5, \ 96 | .Y4_GPIO_NUM = 34, \ 97 | .Y3_GPIO_NUM = 35, \ 98 | .Y2_GPIO_NUM = 32, \ 99 | .VSYNC_GPIO_NUM = 25, \ 100 | .HREF_GPIO_NUM = 26, \ 101 | .PCLK_GPIO_NUM = 21, \ 102 | } 103 | 104 | #define CAMERA_MODEL_M5STACK_WIDE \ 105 | { \ 106 | .PWDN_GPIO_NUM = -1, \ 107 | .RESET_GPIO_NUM = 15, \ 108 | .XCLK_GPIO_NUM = 27, \ 109 | .SIOD_GPIO_NUM = 22, \ 110 | .SIOC_GPIO_NUM = 23, \ 111 | .Y9_GPIO_NUM = 19, \ 112 | .Y8_GPIO_NUM = 36, \ 113 | .Y7_GPIO_NUM = 18, \ 114 | .Y6_GPIO_NUM = 39, \ 115 | .Y5_GPIO_NUM = 5, \ 116 | .Y4_GPIO_NUM = 34, \ 117 | .Y3_GPIO_NUM = 35, \ 118 | .Y2_GPIO_NUM = 32, \ 119 | .VSYNC_GPIO_NUM = 25, \ 120 | .HREF_GPIO_NUM = 26, \ 121 | .PCLK_GPIO_NUM = 21, \ 122 | } 123 | 124 | #define CAMERA_MODEL_M5STACK_ESP32CAM \ 125 | { \ 126 | .PWDN_GPIO_NUM = -1, \ 127 | .RESET_GPIO_NUM = 15, \ 128 | .XCLK_GPIO_NUM = 27, \ 129 | .SIOD_GPIO_NUM = 25, \ 130 | .SIOC_GPIO_NUM = 23, \ 131 | .Y9_GPIO_NUM = 19, \ 132 | .Y8_GPIO_NUM = 36, \ 133 | .Y7_GPIO_NUM = 18, \ 134 | .Y6_GPIO_NUM = 39, \ 135 | .Y5_GPIO_NUM = 5, \ 136 | .Y4_GPIO_NUM = 34, \ 137 | .Y3_GPIO_NUM = 35, \ 138 | .Y2_GPIO_NUM = 17, \ 139 | .VSYNC_GPIO_NUM = 22, \ 140 | .HREF_GPIO_NUM = 26, \ 141 | .PCLK_GPIO_NUM = 21, \ 142 | } 143 | 144 | #define CAMERA_MODEL_AI_THINKER \ 145 | { \ 146 | .PWDN_GPIO_NUM = 32, \ 147 | .RESET_GPIO_NUM = -1, \ 148 | .XCLK_GPIO_NUM = 0, \ 149 | .SIOD_GPIO_NUM = 26, \ 150 | .SIOC_GPIO_NUM = 27, \ 151 | .Y9_GPIO_NUM = 35, \ 152 | .Y8_GPIO_NUM = 34, \ 153 | .Y7_GPIO_NUM = 39, \ 154 | .Y6_GPIO_NUM = 36, \ 155 | .Y5_GPIO_NUM = 21, \ 156 | .Y4_GPIO_NUM = 19, \ 157 | .Y3_GPIO_NUM = 18, \ 158 | .Y2_GPIO_NUM = 5, \ 159 | .VSYNC_GPIO_NUM = 25, \ 160 | .HREF_GPIO_NUM = 23, \ 161 | .PCLK_GPIO_NUM = 22, \ 162 | } 163 | 164 | #define CAMERA_MODEL_TTGO_T_JOURNAL \ 165 | { \ 166 | .PWDN_GPIO_NUM = 0, \ 167 | .RESET_GPIO_NUM = 15, \ 168 | .XCLK_GPIO_NUM = 27, \ 169 | .SIOD_GPIO_NUM = 25, \ 170 | .SIOC_GPIO_NUM = 23, \ 171 | .Y9_GPIO_NUM = 19, \ 172 | .Y8_GPIO_NUM = 36, \ 173 | .Y7_GPIO_NUM = 18, \ 174 | .Y6_GPIO_NUM = 39, \ 175 | .Y5_GPIO_NUM = 5, \ 176 | .Y4_GPIO_NUM = 34, \ 177 | .Y3_GPIO_NUM = 35, \ 178 | .Y2_GPIO_NUM = 17, \ 179 | .VSYNC_GPIO_NUM = 22, \ 180 | .HREF_GPIO_NUM = 26, \ 181 | .PCLK_GPIO_NUM = 21, \ 182 | } 183 | 184 | #endif //ESP32_CAMERA_PINS_H_ -------------------------------------------------------------------------------- /include/ESP32QRCodeReader.h: -------------------------------------------------------------------------------- 1 | #ifndef ESP32_QR_CODE_ARDUINO_H_ 2 | #define ESP32_QR_CODE_ARDUINO_H_ 3 | 4 | #include "Arduino.h" 5 | #include "ESP32CameraPins.h" 6 | #include "esp_camera.h" 7 | 8 | #ifndef QR_CODE_READER_STACK_SIZE 9 | #define QR_CODE_READER_STACK_SIZE 40 * 1024 10 | #endif 11 | 12 | #ifndef QR_CODE_READER_TASK_PRIORITY 13 | #define QR_CODE_READER_TASK_PRIORITY 5 14 | #endif 15 | 16 | enum QRCodeReaderSetupErr 17 | { 18 | SETUP_OK, 19 | SETUP_NO_PSRAM_ERROR, 20 | SETUP_CAMERA_INIT_ERROR, 21 | }; 22 | 23 | /* This structure holds the decoded QR-code data */ 24 | struct QRCodeData 25 | { 26 | bool valid; 27 | int dataType; 28 | uint8_t payload[1024]; 29 | int payloadLen; 30 | }; 31 | 32 | class ESP32QRCodeReader 33 | { 34 | private: 35 | TaskHandle_t qrCodeTaskHandler; 36 | CameraPins pins; 37 | framesize_t frameSize; 38 | 39 | public: 40 | camera_config_t cameraConfig; 41 | QueueHandle_t qrCodeQueue; 42 | bool begun = false; 43 | bool debug = false; 44 | 45 | // Constructor 46 | ESP32QRCodeReader(); 47 | ESP32QRCodeReader(CameraPins pins); 48 | ESP32QRCodeReader(CameraPins pins, framesize_t frameSize); 49 | ESP32QRCodeReader(framesize_t frameSize); 50 | ~ESP32QRCodeReader(); 51 | 52 | // Setup camera 53 | QRCodeReaderSetupErr setup(); 54 | 55 | void begin(); 56 | void beginOnCore(BaseType_t core); 57 | bool receiveQrCode(struct QRCodeData *qrCodeData, long timeoutMs); 58 | void end(); 59 | 60 | void setDebug(bool); 61 | }; 62 | 63 | #endif // ESP32_QR_CODE_ARDUINO_H_ -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ESP32QRCodeReader", 3 | "version": "1.1.0", 4 | "description": "A library to read QR Codes using an ESP32 with a camera module", 5 | "keywords": "qrcode, esp32, camera", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/alvarowolfx/ESP32QRCodeReader" 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Alvaro Viebrantz", 13 | "email": "alvarowolfx@gmail.com", 14 | "url": "https://github.com/alvarowolfx", 15 | "maintainer": true 16 | } 17 | ], 18 | "license": "MIT", 19 | "homepage": "https://github.com/alvarowolfx/ESP32QRCodeReader", 20 | "frameworks": "arduino", 21 | "platforms": "espressif32" 22 | } 23 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESP32QRCodeReader 2 | version=1.1.0 3 | author=Alvaro Viebrantz 4 | maintainer=Alvaro Viebrantz 5 | sentence=A library to read QR Codes using an ESP32 with a camera module. 6 | paragraph=A library to read QR Codes using an ESP32 with a camera module 7 | category=Data Processing 8 | url=https://github.com/alvarowolfx/ESP32QRCodeReader 9 | architectures=* -------------------------------------------------------------------------------- /pio/platformio.ini: -------------------------------------------------------------------------------- 1 | [env:esp32cam] 2 | platform = espressif32 3 | board = esp32cam 4 | framework = arduino 5 | #monitor_port = /dev/tty.usbserial-A50285BI 6 | #upload_port = /dev/tty.usbserial-A50285BI 7 | monitor_speed = 115200 8 | lib_deps= 9 | ESP32QRCodeReader -------------------------------------------------------------------------------- /src/ESP32QRCodeReader.cpp: -------------------------------------------------------------------------------- 1 | #include "ESP32QRCodeReader.h" 2 | 3 | #include "quirc/quirc.h" 4 | #include "Arduino.h" 5 | 6 | ESP32QRCodeReader::ESP32QRCodeReader() : ESP32QRCodeReader(CAMERA_MODEL_AI_THINKER, FRAMESIZE_QVGA) 7 | { 8 | } 9 | 10 | ESP32QRCodeReader::ESP32QRCodeReader(framesize_t frameSize) : ESP32QRCodeReader(CAMERA_MODEL_AI_THINKER, frameSize) 11 | { 12 | } 13 | 14 | ESP32QRCodeReader::ESP32QRCodeReader(CameraPins pins) : ESP32QRCodeReader(pins, FRAMESIZE_QVGA) 15 | { 16 | } 17 | 18 | ESP32QRCodeReader::ESP32QRCodeReader(CameraPins pins, framesize_t frameSize) : pins(pins), frameSize(frameSize) 19 | { 20 | qrCodeQueue = xQueueCreate(10, sizeof(struct QRCodeData)); 21 | } 22 | 23 | ESP32QRCodeReader::~ESP32QRCodeReader() 24 | { 25 | end(); 26 | } 27 | 28 | QRCodeReaderSetupErr ESP32QRCodeReader::setup() 29 | { 30 | if (!psramFound()) 31 | { 32 | return SETUP_NO_PSRAM_ERROR; 33 | } 34 | 35 | cameraConfig.ledc_channel = LEDC_CHANNEL_0; 36 | cameraConfig.ledc_timer = LEDC_TIMER_0; 37 | cameraConfig.pin_d0 = pins.Y2_GPIO_NUM; 38 | cameraConfig.pin_d1 = pins.Y3_GPIO_NUM; 39 | cameraConfig.pin_d2 = pins.Y4_GPIO_NUM; 40 | cameraConfig.pin_d3 = pins.Y5_GPIO_NUM; 41 | cameraConfig.pin_d4 = pins.Y6_GPIO_NUM; 42 | cameraConfig.pin_d5 = pins.Y7_GPIO_NUM; 43 | cameraConfig.pin_d6 = pins.Y8_GPIO_NUM; 44 | cameraConfig.pin_d7 = pins.Y9_GPIO_NUM; 45 | cameraConfig.pin_xclk = pins.XCLK_GPIO_NUM; 46 | cameraConfig.pin_pclk = pins.PCLK_GPIO_NUM; 47 | cameraConfig.pin_vsync = pins.VSYNC_GPIO_NUM; 48 | cameraConfig.pin_href = pins.HREF_GPIO_NUM; 49 | cameraConfig.pin_sscb_sda = pins.SIOD_GPIO_NUM; 50 | cameraConfig.pin_sscb_scl = pins.SIOC_GPIO_NUM; 51 | cameraConfig.pin_pwdn = pins.PWDN_GPIO_NUM; 52 | cameraConfig.pin_reset = pins.RESET_GPIO_NUM; 53 | cameraConfig.xclk_freq_hz = 10000000; 54 | cameraConfig.pixel_format = PIXFORMAT_GRAYSCALE; 55 | 56 | //cameraConfig.frame_size = FRAMESIZE_VGA; 57 | cameraConfig.frame_size = frameSize; 58 | cameraConfig.jpeg_quality = 15; 59 | cameraConfig.fb_count = 1; 60 | 61 | #if defined(CAMERA_MODEL_ESP_EYE) 62 | pinMode(13, INPUT_PULLUP); 63 | pinMode(14, INPUT_PULLUP); 64 | #endif 65 | 66 | // camera init 67 | esp_err_t err = esp_camera_init(&cameraConfig); 68 | if (err != ESP_OK) 69 | { 70 | return SETUP_CAMERA_INIT_ERROR; 71 | } 72 | return SETUP_OK; 73 | } 74 | 75 | void dumpData(const struct quirc_data *data) 76 | { 77 | Serial.printf("Version: %d\n", data->version); 78 | Serial.printf("ECC level: %c\n", "MLHQ"[data->ecc_level]); 79 | Serial.printf("Mask: %d\n", data->mask); 80 | Serial.printf("Length: %d\n", data->payload_len); 81 | Serial.printf("Payload: %s\n", data->payload); 82 | } 83 | 84 | void qrCodeDetectTask(void *taskData) 85 | { 86 | ESP32QRCodeReader *self = (ESP32QRCodeReader *)taskData; 87 | camera_config_t camera_config = self->cameraConfig; 88 | if (camera_config.frame_size > FRAMESIZE_SVGA) 89 | { 90 | if (self->debug) 91 | { 92 | Serial.println("Camera Size err"); 93 | } 94 | vTaskDelete(NULL); 95 | return; 96 | } 97 | 98 | struct quirc *q = NULL; 99 | uint8_t *image = NULL; 100 | camera_fb_t *fb = NULL; 101 | 102 | uint16_t old_width = 0; 103 | uint16_t old_height = 0; 104 | 105 | if (self->debug) 106 | { 107 | Serial.printf("begin to qr_recoginze\r\n"); 108 | } 109 | q = quirc_new(); 110 | if (q == NULL) 111 | { 112 | if (self->debug) 113 | { 114 | Serial.print("can't create quirc object\r\n"); 115 | } 116 | vTaskDelete(NULL); 117 | return; 118 | } 119 | 120 | while (true) 121 | { 122 | 123 | if (self->debug) 124 | { 125 | Serial.printf("alloc qr heap: %u\r\n", xPortGetFreeHeapSize()); 126 | Serial.printf("uxHighWaterMark = %d\r\n", uxTaskGetStackHighWaterMark(NULL)); 127 | Serial.print("begin camera get fb\r\n"); 128 | } 129 | vTaskDelay(100 / portTICK_PERIOD_MS); 130 | 131 | fb = esp_camera_fb_get(); 132 | if (!fb) 133 | { 134 | if (self->debug) 135 | { 136 | Serial.println("Camera capture failed"); 137 | } 138 | continue; 139 | } 140 | 141 | if (old_width != fb->width || old_height != fb->height) 142 | { 143 | if (self->debug) 144 | { 145 | Serial.printf("Recognizer size change w h len: %d, %d, %d \r\n", fb->width, fb->height, fb->len); 146 | Serial.println("Resize the QR-code recognizer."); 147 | // Resize the QR-code recognizer. 148 | } 149 | if (quirc_resize(q, fb->width, fb->height) < 0) 150 | { 151 | if (self->debug) 152 | { 153 | Serial.println("Resize the QR-code recognizer err (cannot allocate memory)."); 154 | } 155 | esp_camera_fb_return(fb); 156 | fb = NULL; 157 | image = NULL; 158 | continue; 159 | } 160 | else 161 | { 162 | old_width = fb->width; 163 | old_height = fb->height; 164 | } 165 | } 166 | 167 | // Serial.printf("quirc_begin\r\n"); 168 | image = quirc_begin(q, NULL, NULL); 169 | if (self->debug) 170 | { 171 | Serial.printf("Frame w h len: %d, %d, %d \r\n", fb->width, fb->height, fb->len); 172 | } 173 | memcpy(image, fb->buf, fb->len); 174 | quirc_end(q); 175 | 176 | if (self->debug) 177 | { 178 | Serial.printf("quirc_end\r\n"); 179 | } 180 | int count = quirc_count(q); 181 | if (count == 0) 182 | { 183 | if (self->debug) 184 | { 185 | Serial.printf("Error: not a valid qrcode\n"); 186 | } 187 | esp_camera_fb_return(fb); 188 | fb = NULL; 189 | image = NULL; 190 | continue; 191 | } 192 | 193 | for (int i = 0; i < count; i++) 194 | { 195 | struct quirc_code code; 196 | struct quirc_data data; 197 | quirc_decode_error_t err; 198 | 199 | quirc_extract(q, i, &code); 200 | err = quirc_decode(&code, &data); 201 | 202 | struct QRCodeData qrCodeData; 203 | 204 | if (err) 205 | { 206 | const char *error = quirc_strerror(err); 207 | int len = strlen(error); 208 | if (self->debug) 209 | { 210 | Serial.printf("Decoding FAILED: %s\n", error); 211 | } 212 | for (int i = 0; i < len; i++) 213 | { 214 | qrCodeData.payload[i] = error[i]; 215 | } 216 | qrCodeData.valid = false; 217 | qrCodeData.payload[len] = '\0'; 218 | qrCodeData.payloadLen = len; 219 | } 220 | else 221 | { 222 | if (self->debug) 223 | { 224 | Serial.printf("Decoding successful:\n"); 225 | dumpData(&data); 226 | } 227 | 228 | qrCodeData.dataType = data.data_type; 229 | for (int i = 0; i < data.payload_len; i++) 230 | { 231 | qrCodeData.payload[i] = data.payload[i]; 232 | } 233 | qrCodeData.valid = true; 234 | qrCodeData.payload[data.payload_len] = '\0'; 235 | qrCodeData.payloadLen = data.payload_len; 236 | } 237 | xQueueSend(self->qrCodeQueue, &qrCodeData, (TickType_t)0); 238 | 239 | if (self->debug) 240 | { 241 | Serial.println(); 242 | } 243 | } 244 | 245 | //Serial.printf("finish recoginize\r\n"); 246 | esp_camera_fb_return(fb); 247 | fb = NULL; 248 | image = NULL; 249 | } 250 | quirc_destroy(q); 251 | vTaskDelete(NULL); 252 | } 253 | 254 | void ESP32QRCodeReader::begin() 255 | { 256 | beginOnCore(0); 257 | } 258 | 259 | void ESP32QRCodeReader::beginOnCore(BaseType_t core) 260 | { 261 | if (!begun) 262 | { 263 | xTaskCreatePinnedToCore(qrCodeDetectTask, "qrCodeDetectTask", QR_CODE_READER_STACK_SIZE, this, QR_CODE_READER_TASK_PRIORITY, &qrCodeTaskHandler, core); 264 | begun = true; 265 | } 266 | } 267 | 268 | bool ESP32QRCodeReader::receiveQrCode(struct QRCodeData *qrCodeData, long timeoutMs) 269 | { 270 | return xQueueReceive(qrCodeQueue, qrCodeData, (TickType_t)pdMS_TO_TICKS(timeoutMs)) != 0; 271 | } 272 | 273 | void ESP32QRCodeReader::end() 274 | { 275 | if (begun) 276 | { 277 | TaskHandle_t tmpTask = qrCodeTaskHandler; 278 | if (qrCodeTaskHandler != NULL) 279 | { 280 | qrCodeTaskHandler = NULL; 281 | vTaskDelete(tmpTask); 282 | } 283 | } 284 | begun = false; 285 | } 286 | 287 | void ESP32QRCodeReader::setDebug(bool on) 288 | { 289 | debug = on; 290 | } 291 | -------------------------------------------------------------------------------- /src/openmv/collections.c: -------------------------------------------------------------------------------- 1 | /* This file is part of the OpenMV project. 2 | * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman 3 | * This work is licensed under the MIT license, see the file LICENSE for details. 4 | */ 5 | 6 | #include "collections.h" 7 | #define CHAR_BITS (sizeof(char) * 8) 8 | #define CHAR_MASK (CHAR_BITS - 1) 9 | #define CHAR_SHIFT IM_LOG2(CHAR_MASK) 10 | 11 | ////////// 12 | // lifo // 13 | ////////// 14 | 15 | void lifo_alloc(lifo_t *ptr, size_t size, size_t data_len) 16 | { 17 | ptr->len = 0; 18 | ptr->size = size; 19 | ptr->data_len = data_len; 20 | ptr->data = (char *)ps_malloc(size * data_len); 21 | } 22 | 23 | void lifo_alloc_all(lifo_t *ptr, size_t *size, size_t data_len) 24 | { 25 | ptr->data = (char *)ps_malloc(255); 26 | ptr->data_len = data_len; 27 | ptr->size = 255 / data_len; 28 | ptr->len = 0; 29 | *size = ptr->size; 30 | } 31 | 32 | void lifo_free(lifo_t *ptr) 33 | { 34 | if (ptr->data) 35 | { 36 | free(ptr->data); 37 | } 38 | } 39 | 40 | void lifo_clear(lifo_t *ptr) 41 | { 42 | ptr->len = 0; 43 | } 44 | 45 | size_t lifo_size(lifo_t *ptr) 46 | { 47 | return ptr->len; 48 | } 49 | 50 | bool lifo_is_not_empty(lifo_t *ptr) 51 | { 52 | return ptr->len; 53 | } 54 | 55 | bool lifo_is_not_full(lifo_t *ptr) 56 | { 57 | return ptr->len != ptr->size; 58 | } 59 | 60 | void lifo_enqueue(lifo_t *ptr, void *data) 61 | { 62 | memcpy(ptr->data + (ptr->len * ptr->data_len), data, ptr->data_len); 63 | 64 | ptr->len += 1; 65 | } 66 | 67 | void lifo_dequeue(lifo_t *ptr, void *data) 68 | { 69 | if (data) 70 | { 71 | memcpy(data, ptr->data + ((ptr->len - 1) * ptr->data_len), ptr->data_len); 72 | } 73 | 74 | ptr->len -= 1; 75 | } 76 | 77 | void lifo_poke(lifo_t *ptr, void *data) 78 | { 79 | memcpy(ptr->data + (ptr->len * ptr->data_len), data, ptr->data_len); 80 | } 81 | 82 | void lifo_peek(lifo_t *ptr, void *data) 83 | { 84 | memcpy(data, ptr->data + ((ptr->len - 1) * ptr->data_len), ptr->data_len); 85 | } 86 | -------------------------------------------------------------------------------- /src/openmv/collections.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the OpenMV project. 2 | * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman 3 | * This work is licensed under the MIT license, see the file LICENSE for details. 4 | */ 5 | 6 | #ifndef __COLLECTIONS_H__ 7 | #define __COLLECTIONS_H__ 8 | #include 9 | #include 10 | ////////// 11 | // lifo // 12 | ////////// 13 | 14 | typedef struct lifo 15 | { 16 | size_t len, size, data_len; 17 | char *data; 18 | } 19 | __attribute__((aligned(8))) lifo_t; 20 | 21 | void lifo_alloc(lifo_t *ptr, size_t size, size_t data_len); 22 | void lifo_alloc_all(lifo_t *ptr, size_t *size, size_t data_len); 23 | void lifo_free(lifo_t *ptr); 24 | void lifo_clear(lifo_t *ptr); 25 | size_t lifo_size(lifo_t *ptr); 26 | bool lifo_is_not_empty(lifo_t *ptr); 27 | bool lifo_is_not_full(lifo_t *ptr); 28 | void lifo_enqueue(lifo_t *ptr, void *data); 29 | void lifo_dequeue(lifo_t *ptr, void *data); 30 | void lifo_poke(lifo_t *ptr, void *data); 31 | void lifo_peek(lifo_t *ptr, void *data); 32 | 33 | #endif /* __COLLECTIONS_H__ */ -------------------------------------------------------------------------------- /src/openmv/fmath.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * Fast approximate math functions. 7 | * 8 | */ 9 | #ifndef __FMATH_H 10 | #define __FMATH_H 11 | #include 12 | #include 13 | 14 | static inline float fast_sqrtf(float x) 15 | { 16 | //return sqrtf(x); 17 | asm("fsqrt.s %0, %1" 18 | : "=f"(x) 19 | : "f"(x)); 20 | return x; 21 | } 22 | static inline int fast_floorf(float x) 23 | { 24 | return (int)(x); 25 | } 26 | 27 | static inline int fast_ceilf(float x) 28 | { 29 | return (int)(x + 0.9999f); 30 | } 31 | 32 | static inline int fast_roundf(float x) 33 | { 34 | return (int)(x); 35 | } 36 | 37 | static inline float fast_fabsf(float d) 38 | { 39 | return fabsf(d); 40 | } 41 | 42 | extern int fast_floorf(float x); 43 | extern int fast_ceilf(float x); 44 | extern int fast_roundf(float x); 45 | extern float fast_atanf(float x); 46 | extern float fast_atan2f(float y, float x); 47 | extern float fast_expf(float x); 48 | extern float fast_cbrtf(float d); 49 | extern float fast_fabsf(float d); 50 | extern float fast_log(float x); 51 | extern float fast_log2(float x); 52 | extern float fast_powf(float a, float b); 53 | 54 | /*#define fast_sqrtf(x) (sqrtf(x)) 55 | #define fast_floorf(x) ((int)floorf(x)) 56 | #define fast_ceilf(x) ((int)ceilf(x)) 57 | #define fast_roundf(x) ((int)roundf(x)) 58 | #define fast_atanf(x) (atanf(x)) 59 | #define fast_atan2f(x,y) (atan2f((x),(y))) 60 | #define fast_expf(x) (expf(x)) 61 | #define fast_cbrtf(x) (cbrtf(x)) 62 | #define fast_fabsf(x) (fabsf(x)) 63 | #define fast_log(x) (log(x)) 64 | #define fast_log2(x) (log2(x)) 65 | #define fast_powf(x,y) (powf((x),(y))) 66 | */ 67 | 68 | extern const float cos_table[360]; 69 | extern const float sin_table[360]; 70 | #endif // __FMATH_H -------------------------------------------------------------------------------- /src/quirc/LICENSE: -------------------------------------------------------------------------------- 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 5 | any purpose with or without fee is hereby granted, provided that the 6 | above copyright notice and this permission notice appear in all 7 | copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 | PERFORMANCE OF THIS SOFTWARE. 17 | -------------------------------------------------------------------------------- /src/quirc/README.md: -------------------------------------------------------------------------------- 1 | Quirc 2 | ===== 3 | 4 | QR codes are a type of high-density matrix barcodes, and quirc is a library for 5 | extracting and decoding them from images. It has several features which make it 6 | a good choice for this purpose: 7 | 8 | * It is fast enough to be used with realtime video: extracting and decoding 9 | from VGA frame takes about 50 ms on a modern x86 core. 10 | 11 | * It has a robust and tolerant recognition algorithm. It can correctly 12 | recognise and decode QR codes which are rotated and/or oblique to the camera. 13 | It can also distinguish and decode multiple codes within the same image. 14 | 15 | * It is easy to use, with a simple API described in a single commented header 16 | file (see below for an overview). 17 | 18 | * It is small and easily embeddable, with no dependencies other than standard C 19 | functions. 20 | 21 | * It has a very small memory footprint: one byte per image pixel, plus a few kB 22 | per decoder object. 23 | 24 | * It uses no global mutable state, and is safe to use in a multithreaded 25 | application. 26 | 27 | * BSD-licensed, with almost no restrictions regarding use and/or modification. 28 | 29 | The distribution comes with, in addition to the library, several test programs. 30 | While the core library is very portable, these programs have some additional 31 | dependencies. All of them require libjpeg, and two (`quirc-demo` and `inspect`) 32 | require SDL. The camera demos use Linux-specific APIs: 33 | 34 | ### quirc-demo 35 | 36 | This is an real-time demo which requires a camera and a graphical display. The 37 | video stream is displayed on screen as it's received, and any QR codes 38 | recognised are highlighted in the image, with the decoded information both 39 | displayed on the image and printed on stdout. 40 | 41 | ### quirc-scanner 42 | 43 | This program turns your camera into a barcode scanner. It's almost the same as 44 | the `demo` application, but it doesn't display the video stream, and thus 45 | doesn't require a graphical display. 46 | 47 | ### qrtest 48 | 49 | This test is used to evaluate the performance of library. Given a directory 50 | tree containing a bunch of JPEG images, it will attempt to locate and decode QR 51 | codes in each image. Speed and success statistics are collected and printed on 52 | stdout. 53 | 54 | ### inspect 55 | 56 | This test is used for debugging. Given a single JPEG image, it will display a 57 | diagram showing the internal state of the decoder as well as printing 58 | additional information on stdout. 59 | 60 | Installation 61 | ------------ 62 | To build the library and associated demos/tests, type `make`. If you need to 63 | decode "large" image files build with `CFLAGS="-DQUIRC_MAX_REGIONS=65534" make` 64 | instead. Note that this will increase the memory usage, it is discouraged for 65 | low resource devices (i.e. embedded). 66 | 67 | Type `make install` to install the library, header file and camera demos. 68 | 69 | You can specify one or several of the following targets if you don't want, or 70 | are unable to build everything: 71 | 72 | * libquirc.a 73 | * libquirc.so 74 | * qrtest 75 | * inspect 76 | * quirc-scanner 77 | * quirc-demo 78 | 79 | Library use 80 | ----------- 81 | All of the library's functionality is exposed through a single header file, 82 | which you should include: 83 | 84 | ```C 85 | #include 86 | ``` 87 | 88 | To decode images, you'll need to instantiate a `struct quirc` object, which is 89 | done with the `quirc_new` function. Later, when you no longer need to decode 90 | anything, you should release the allocated memory with `quirc_destroy`: 91 | 92 | ```C 93 | struct quirc *qr; 94 | 95 | qr = quirc_new(); 96 | if (!qr) { 97 | perror("Failed to allocate memory"); 98 | abort(); 99 | } 100 | 101 | /* ... */ 102 | 103 | quirc_destroy(qr); 104 | ``` 105 | 106 | Having obtained a decoder object, you need to set the image size that you'll be 107 | working with, which is done using `quirc_resize`: 108 | 109 | ```C 110 | if (quirc_resize(qr, 640, 480) < 0) { 111 | perror("Failed to allocate video memory"); 112 | abort(); 113 | } 114 | ``` 115 | 116 | `quirc_resize` and `quirc_new` are the only library functions which allocate 117 | memory. If you plan to process a series of frames (or a video stream), you 118 | probably want to allocate and size a single decoder and hold onto it to process 119 | each frame. 120 | 121 | Processing frames is done in two stages. The first stage is an 122 | image-recognition stage called identification, which takes a grayscale image 123 | and searches for QR codes. Using `quirc_begin` and `quirc_end`, you can feed a 124 | grayscale image directly into the buffer that `quirc` uses for image 125 | processing: 126 | 127 | ```C 128 | uint8_t *image; 129 | int w, h; 130 | 131 | image = quirc_begin(qr, &w, &h); 132 | 133 | /* Fill out the image buffer here. 134 | * image is a pointer to a w*h bytes. 135 | * One byte per pixel, w pixels per line, h lines in the buffer. 136 | */ 137 | 138 | quirc_end(qr); 139 | ``` 140 | 141 | Note that `quirc_begin` simply returns a pointer to a previously allocated 142 | buffer. The buffer will contain uninitialized data. After the call to 143 | `quirc_end`, the decoder holds a list of detected QR codes which can be queried 144 | via `quirc_count` and `quirc_extract`. 145 | 146 | At this point, the second stage of processing occurs -- decoding. This is done 147 | via the call to `quirc_decode`, which is not associated with a decoder object. 148 | 149 | ```C 150 | int num_codes; 151 | int i; 152 | 153 | /* We've previously fed an image to the decoder via 154 | * quirc_begin/quirc_end. 155 | */ 156 | 157 | num_codes = quirc_count(qr); 158 | for (i = 0; i < num_codes; i++) { 159 | struct quirc_code code; 160 | struct quirc_data data; 161 | quirc_decode_error_t err; 162 | 163 | quirc_extract(qr, i, &code); 164 | 165 | /* Decoding stage */ 166 | err = quirc_decode(&code, &data); 167 | if (err) 168 | printf("DECODE FAILED: %s\n", quirc_strerror(err)); 169 | else 170 | printf("Data: %s\n", data.payload); 171 | } 172 | ``` 173 | 174 | `quirc_code` and `quirc_data` are flat structures which don't need to be 175 | initialized or freed after use. 176 | 177 | Copyright 178 | --------- 179 | Copyright (C) 2010-2012 Daniel Beer <> 180 | 181 | Permission to use, copy, modify, and/or distribute this software for 182 | any purpose with or without fee is hereby granted, provided that the 183 | above copyright notice and this permission notice appear in all 184 | copies. 185 | 186 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 187 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 188 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 189 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 190 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 191 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 192 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 193 | PERFORMANCE OF THIS SOFTWARE. 194 | -------------------------------------------------------------------------------- /src/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 | { 30 | int p; 31 | const uint8_t *log; 32 | const uint8_t *exp; 33 | } __attribute__((aligned(8))); 34 | 35 | static const uint8_t gf16_exp[16] = { 36 | 0x01, 0x02, 0x04, 0x08, 0x03, 0x06, 0x0c, 0x0b, 37 | 0x05, 0x0a, 0x07, 0x0e, 0x0f, 0x0d, 0x09, 0x01}; 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 | static const struct galois_field gf16 = { 44 | .p = 15, 45 | .log = gf16_log, 46 | .exp = gf16_exp}; 47 | 48 | static const uint8_t gf256_exp[256] = { 49 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 50 | 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 51 | 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 52 | 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 53 | 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 54 | 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 55 | 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 56 | 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 57 | 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 58 | 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 59 | 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 60 | 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, 61 | 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 62 | 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 63 | 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 64 | 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 65 | 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 66 | 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, 67 | 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 68 | 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 69 | 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 70 | 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 71 | 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 72 | 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, 73 | 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 74 | 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 75 | 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 76 | 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, 77 | 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 78 | 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, 79 | 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 80 | 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01}; 81 | 82 | static const uint8_t gf256_log[256] = { 83 | 0x00, 0xff, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 84 | 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 85 | 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 86 | 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, 87 | 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 88 | 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 89 | 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 90 | 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 91 | 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 92 | 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 93 | 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 94 | 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, 95 | 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 96 | 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, 97 | 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 98 | 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 99 | 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 100 | 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, 101 | 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 102 | 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 103 | 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 104 | 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 105 | 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 106 | 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, 107 | 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 108 | 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, 109 | 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 110 | 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 111 | 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 112 | 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, 113 | 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 114 | 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf}; 115 | 116 | const static struct galois_field gf256 = { 117 | .p = 255, 118 | .log = gf256_log, 119 | .exp = gf256_exp}; 120 | 121 | /************************************************************************ 122 | * Polynomial operations 123 | */ 124 | 125 | static void poly_add(uint8_t *dst, const uint8_t *src, uint8_t c, 126 | int shift, const struct galois_field *gf) 127 | { 128 | int i; 129 | int log_c = gf->log[c]; 130 | 131 | if (!c) 132 | return; 133 | 134 | for (i = 0; i < MAX_POLY; i++) 135 | { 136 | int p = i + shift; 137 | uint8_t v = src[i]; 138 | 139 | if (p < 0 || p >= MAX_POLY) 140 | continue; 141 | if (!v) 142 | continue; 143 | 144 | dst[p] ^= gf->exp[(gf->log[v] + log_c) % gf->p]; 145 | } 146 | } 147 | 148 | static uint8_t poly_eval(const uint8_t *s, uint8_t x, 149 | const struct galois_field *gf) 150 | { 151 | int i; 152 | uint8_t sum = 0; 153 | uint8_t log_x = gf->log[x]; 154 | 155 | if (!x) 156 | return s[0]; 157 | 158 | for (i = 0; i < MAX_POLY; i++) 159 | { 160 | uint8_t c = s[i]; 161 | 162 | if (!c) 163 | continue; 164 | 165 | sum ^= gf->exp[(gf->log[c] + log_x * i) % gf->p]; 166 | } 167 | 168 | return sum; 169 | } 170 | 171 | /************************************************************************ 172 | * Berlekamp-Massey algorithm for finding error locator polynomials. 173 | */ 174 | 175 | static void berlekamp_massey(const uint8_t *s, int N, 176 | const struct galois_field *gf, 177 | uint8_t *sigma) 178 | { 179 | uint8_t C[MAX_POLY]; 180 | uint8_t B[MAX_POLY]; 181 | int L = 0; 182 | int m = 1; 183 | uint8_t b = 1; 184 | int n; 185 | 186 | memset(B, 0, sizeof(B)); 187 | memset(C, 0, sizeof(C)); 188 | B[0] = 1; 189 | C[0] = 1; 190 | 191 | for (n = 0; n < N; n++) 192 | { 193 | uint8_t d = s[n]; 194 | uint8_t mult; 195 | int i; 196 | 197 | for (i = 1; i <= L; i++) 198 | { 199 | if (!(C[i] && s[n - i])) 200 | continue; 201 | 202 | d ^= gf->exp[(gf->log[C[i]] + 203 | gf->log[s[n - i]]) % 204 | gf->p]; 205 | } 206 | 207 | mult = gf->exp[(gf->p - gf->log[b] + gf->log[d]) % gf->p]; 208 | 209 | if (!d) 210 | { 211 | m++; 212 | } 213 | else if (L * 2 <= n) 214 | { 215 | uint8_t T[MAX_POLY]; 216 | 217 | memcpy(T, C, sizeof(T)); 218 | poly_add(C, B, mult, m, gf); 219 | memcpy(B, T, sizeof(B)); 220 | L = n + 1 - L; 221 | b = d; 222 | m = 1; 223 | } 224 | else 225 | { 226 | poly_add(C, B, mult, m, gf); 227 | m++; 228 | } 229 | } 230 | 231 | memcpy(sigma, C, MAX_POLY); 232 | } 233 | 234 | /************************************************************************ 235 | * Code stream error correction 236 | * 237 | * Generator polynomial for GF(2^8) is x^8 + x^4 + x^3 + x^2 + 1 238 | */ 239 | 240 | static int block_syndromes(const uint8_t *data, int bs, int npar, uint8_t *s) 241 | { 242 | int nonzero = 0; 243 | int i; 244 | 245 | memset(s, 0, MAX_POLY); 246 | 247 | for (i = 0; i < npar; i++) 248 | { 249 | int j; 250 | 251 | for (j = 0; j < bs; j++) 252 | { 253 | uint8_t c = data[bs - j - 1]; 254 | 255 | if (!c) 256 | continue; 257 | 258 | s[i] ^= gf256_exp[((int)gf256_log[c] + 259 | i * j) % 260 | 255]; 261 | } 262 | 263 | if (s[i]) 264 | nonzero = 1; 265 | } 266 | 267 | return nonzero; 268 | } 269 | 270 | static void eloc_poly(uint8_t *omega, 271 | const uint8_t *s, const uint8_t *sigma, 272 | int npar) 273 | { 274 | int i; 275 | 276 | memset(omega, 0, MAX_POLY); 277 | 278 | for (i = 0; i < npar; i++) 279 | { 280 | const uint8_t a = sigma[i]; 281 | const uint8_t log_a = gf256_log[a]; 282 | int j; 283 | 284 | if (!a) 285 | continue; 286 | 287 | for (j = 0; j + 1 < MAX_POLY; j++) 288 | { 289 | const uint8_t b = s[j + 1]; 290 | 291 | if (i + j >= npar) 292 | break; 293 | 294 | if (!b) 295 | continue; 296 | 297 | omega[i + j] ^= 298 | gf256_exp[(log_a + gf256_log[b]) % 255]; 299 | } 300 | } 301 | } 302 | 303 | static quirc_decode_error_t correct_block(uint8_t *data, 304 | const struct quirc_rs_params *ecc) 305 | { 306 | int npar = ecc->bs - ecc->dw; 307 | uint8_t s[MAX_POLY]; 308 | uint8_t sigma[MAX_POLY]; 309 | uint8_t sigma_deriv[MAX_POLY]; 310 | uint8_t omega[MAX_POLY]; 311 | int i; 312 | 313 | /* Compute syndrome vector */ 314 | if (!block_syndromes(data, ecc->bs, npar, s)) 315 | return QUIRC_SUCCESS; 316 | 317 | berlekamp_massey(s, npar, &gf256, sigma); 318 | 319 | /* Compute derivative of sigma */ 320 | memset(sigma_deriv, 0, MAX_POLY); 321 | for (i = 0; i + 1 < MAX_POLY; i += 2) 322 | sigma_deriv[i] = sigma[i + 1]; 323 | 324 | /* Compute error evaluator polynomial */ 325 | eloc_poly(omega, s, sigma, npar - 1); 326 | 327 | /* Find error locations and magnitudes */ 328 | for (i = 0; i < ecc->bs; i++) 329 | { 330 | uint8_t xinv = gf256_exp[255 - i]; 331 | 332 | if (!poly_eval(sigma, xinv, &gf256)) 333 | { 334 | uint8_t sd_x = poly_eval(sigma_deriv, xinv, &gf256); 335 | uint8_t omega_x = poly_eval(omega, xinv, &gf256); 336 | uint8_t error = gf256_exp[(255 - gf256_log[sd_x] + 337 | gf256_log[omega_x]) % 338 | 255]; 339 | 340 | data[ecc->bs - i - 1] ^= error; 341 | } 342 | } 343 | 344 | if (block_syndromes(data, ecc->bs, npar, s)) 345 | return QUIRC_ERROR_DATA_ECC; 346 | 347 | return QUIRC_SUCCESS; 348 | } 349 | 350 | /************************************************************************ 351 | * Format value error correction 352 | * 353 | * Generator polynomial for GF(2^4) is x^4 + x + 1 354 | */ 355 | 356 | #define FORMAT_MAX_ERROR 3 357 | #define FORMAT_SYNDROMES (FORMAT_MAX_ERROR * 2) 358 | #define FORMAT_BITS 15 359 | 360 | static int format_syndromes(uint16_t u, uint8_t *s) 361 | { 362 | int i; 363 | int nonzero = 0; 364 | 365 | memset(s, 0, MAX_POLY); 366 | 367 | for (i = 0; i < FORMAT_SYNDROMES; i++) 368 | { 369 | int j; 370 | 371 | s[i] = 0; 372 | for (j = 0; j < FORMAT_BITS; j++) 373 | if (u & (1 << j)) 374 | s[i] ^= gf16_exp[((i + 1) * j) % 15]; 375 | 376 | if (s[i]) 377 | nonzero = 1; 378 | } 379 | 380 | return nonzero; 381 | } 382 | 383 | static quirc_decode_error_t correct_format(uint16_t *f_ret) 384 | { 385 | uint16_t u = *f_ret; 386 | int i; 387 | uint8_t s[MAX_POLY]; 388 | uint8_t sigma[MAX_POLY]; 389 | 390 | /* Evaluate U (received codeword) at each of alpha_1 .. alpha_6 391 | * to get S_1 .. S_6 (but we index them from 0). 392 | */ 393 | if (!format_syndromes(u, s)) 394 | return QUIRC_SUCCESS; 395 | 396 | berlekamp_massey(s, FORMAT_SYNDROMES, &gf16, sigma); 397 | 398 | /* Now, find the roots of the polynomial */ 399 | for (i = 0; i < 15; i++) 400 | if (!poly_eval(sigma, gf16_exp[15 - i], &gf16)) 401 | u ^= (1 << i); 402 | 403 | if (format_syndromes(u, s)) 404 | return QUIRC_ERROR_FORMAT_ECC; 405 | 406 | *f_ret = u; 407 | return QUIRC_SUCCESS; 408 | } 409 | 410 | /************************************************************************ 411 | * Decoder algorithm 412 | */ 413 | 414 | struct datastream 415 | { 416 | uint8_t raw[QUIRC_MAX_PAYLOAD]; 417 | int data_bits; 418 | int ptr; 419 | 420 | uint8_t data[QUIRC_MAX_PAYLOAD]; 421 | } __attribute__((aligned(8))); 422 | 423 | static inline int grid_bit(const struct quirc_code *code, int x, int y) 424 | { 425 | int p = y * code->size + x; 426 | 427 | return (code->cell_bitmap[p >> 3] >> (p & 7)) & 1; 428 | } 429 | 430 | static quirc_decode_error_t read_format(const struct quirc_code *code, 431 | struct quirc_data *data, int which) 432 | { 433 | int i; 434 | uint16_t format = 0; 435 | uint16_t fdata; 436 | quirc_decode_error_t err; 437 | 438 | if (which) 439 | { 440 | for (i = 0; i < 7; i++) 441 | format = (format << 1) | 442 | grid_bit(code, 8, code->size - 1 - i); 443 | for (i = 0; i < 8; i++) 444 | format = (format << 1) | 445 | grid_bit(code, code->size - 8 + i, 8); 446 | } 447 | else 448 | { 449 | static const int xs[15] = { 450 | 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 4, 3, 2, 1, 0}; 451 | static const int ys[15] = { 452 | 0, 1, 2, 3, 4, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8}; 453 | 454 | for (i = 14; i >= 0; i--) 455 | format = (format << 1) | grid_bit(code, xs[i], ys[i]); 456 | } 457 | 458 | format ^= 0x5412; 459 | 460 | err = correct_format(&format); 461 | if (err) 462 | return err; 463 | 464 | fdata = format >> 10; 465 | data->ecc_level = fdata >> 3; 466 | data->mask = fdata & 7; 467 | 468 | return QUIRC_SUCCESS; 469 | } 470 | 471 | static int mask_bit(int mask, int i, int j) 472 | { 473 | switch (mask) 474 | { 475 | case 0: 476 | return !((i + j) % 2); 477 | case 1: 478 | return !(i % 2); 479 | case 2: 480 | return !(j % 3); 481 | case 3: 482 | return !((i + j) % 3); 483 | case 4: 484 | return !(((i / 2) + (j / 3)) % 2); 485 | case 5: 486 | return !((i * j) % 2 + (i * j) % 3); 487 | case 6: 488 | return !(((i * j) % 2 + (i * j) % 3) % 2); 489 | case 7: 490 | return !(((i * j) % 3 + (i + j) % 2) % 2); 491 | } 492 | 493 | return 0; 494 | } 495 | 496 | static int reserved_cell(int version, int i, int j) 497 | { 498 | const struct quirc_version_info *ver = &quirc_version_db[version]; 499 | int size = version * 4 + 17; 500 | int ai = -1, aj = -1, a; 501 | 502 | /* Finder + format: top left */ 503 | if (i < 9 && j < 9) 504 | return 1; 505 | 506 | /* Finder + format: bottom left */ 507 | if (i + 8 >= size && j < 9) 508 | return 1; 509 | 510 | /* Finder + format: top right */ 511 | if (i < 9 && j + 8 >= size) 512 | return 1; 513 | 514 | /* Exclude timing patterns */ 515 | if (i == 6 || j == 6) 516 | return 1; 517 | 518 | /* Exclude version info, if it exists. Version info sits adjacent to 519 | * the top-right and bottom-left finders in three rows, bounded by 520 | * the timing pattern. 521 | */ 522 | if (version >= 7) 523 | { 524 | if (i < 6 && j + 11 >= size) 525 | return 1; 526 | if (i + 11 >= size && j < 6) 527 | return 1; 528 | } 529 | 530 | /* Exclude alignment patterns */ 531 | for (a = 0; a < QUIRC_MAX_ALIGNMENT && ver->apat[a]; a++) 532 | { 533 | int p = ver->apat[a]; 534 | 535 | if (abs(p - i) < 3) 536 | ai = a; 537 | if (abs(p - j) < 3) 538 | aj = a; 539 | } 540 | 541 | if (ai >= 0 && aj >= 0) 542 | { 543 | a--; 544 | if (ai > 0 && ai < a) 545 | return 1; 546 | if (aj > 0 && aj < a) 547 | return 1; 548 | if (aj == a && ai == a) 549 | return 1; 550 | } 551 | 552 | return 0; 553 | } 554 | 555 | static void read_bit(const struct quirc_code *code, 556 | struct quirc_data *data, 557 | struct datastream *ds, int i, int j) 558 | { 559 | int bitpos = ds->data_bits & 7; 560 | int bytepos = ds->data_bits >> 3; 561 | int v = grid_bit(code, j, i); 562 | 563 | if (mask_bit(data->mask, i, j)) 564 | v ^= 1; 565 | 566 | if (v) 567 | ds->raw[bytepos] |= (0x80 >> bitpos); 568 | 569 | ds->data_bits++; 570 | } 571 | 572 | static void read_data(const struct quirc_code *code, 573 | struct quirc_data *data, 574 | struct datastream *ds) 575 | { 576 | int y = code->size - 1; 577 | int x = code->size - 1; 578 | int dir = -1; 579 | 580 | while (x > 0) 581 | { 582 | if (x == 6) 583 | x--; 584 | 585 | if (!reserved_cell(data->version, y, x)) 586 | read_bit(code, data, ds, y, x); 587 | 588 | if (!reserved_cell(data->version, y, x - 1)) 589 | read_bit(code, data, ds, y, x - 1); 590 | 591 | y += dir; 592 | if (y < 0 || y >= code->size) 593 | { 594 | dir = -dir; 595 | x -= 2; 596 | y += dir; 597 | } 598 | } 599 | } 600 | 601 | static quirc_decode_error_t codestream_ecc(struct quirc_data *data, 602 | struct datastream *ds) 603 | { 604 | const struct quirc_version_info *ver = 605 | &quirc_version_db[data->version]; 606 | const struct quirc_rs_params *sb_ecc = &ver->ecc[data->ecc_level]; 607 | struct quirc_rs_params lb_ecc; 608 | const int lb_count = 609 | (ver->data_bytes - sb_ecc->bs * sb_ecc->ns) / (sb_ecc->bs + 1); 610 | const int bc = lb_count + sb_ecc->ns; 611 | const int ecc_offset = sb_ecc->dw * bc + lb_count; 612 | int dst_offset = 0; 613 | int i; 614 | 615 | memcpy(&lb_ecc, sb_ecc, sizeof(lb_ecc)); 616 | lb_ecc.dw++; 617 | lb_ecc.bs++; 618 | 619 | for (i = 0; i < bc; i++) 620 | { 621 | uint8_t *dst = ds->data + dst_offset; 622 | const struct quirc_rs_params *ecc = 623 | (i < sb_ecc->ns) ? sb_ecc : &lb_ecc; 624 | const int num_ec = ecc->bs - ecc->dw; 625 | quirc_decode_error_t err; 626 | int j; 627 | 628 | for (j = 0; j < ecc->dw; j++) 629 | dst[j] = ds->raw[j * bc + i]; 630 | for (j = 0; j < num_ec; j++) 631 | dst[ecc->dw + j] = ds->raw[ecc_offset + j * bc + i]; 632 | 633 | err = correct_block(dst, ecc); 634 | if (err) 635 | return err; 636 | 637 | dst_offset += ecc->dw; 638 | } 639 | 640 | ds->data_bits = dst_offset * 8; 641 | 642 | return QUIRC_SUCCESS; 643 | } 644 | 645 | static inline int bits_remaining(const struct datastream *ds) 646 | { 647 | return ds->data_bits - ds->ptr; 648 | } 649 | 650 | static int take_bits(struct datastream *ds, int len) 651 | { 652 | int ret = 0; 653 | 654 | while (len && (ds->ptr < ds->data_bits)) 655 | { 656 | uint8_t b = ds->data[ds->ptr >> 3]; 657 | int bitpos = ds->ptr & 7; 658 | 659 | ret <<= 1; 660 | if ((b << bitpos) & 0x80) 661 | ret |= 1; 662 | 663 | ds->ptr++; 664 | len--; 665 | } 666 | 667 | return ret; 668 | } 669 | 670 | static int numeric_tuple(struct quirc_data *data, 671 | struct datastream *ds, 672 | int bits, int digits) 673 | { 674 | int tuple; 675 | int i; 676 | 677 | if (bits_remaining(ds) < bits) 678 | return -1; 679 | 680 | tuple = take_bits(ds, bits); 681 | 682 | for (i = digits - 1; i >= 0; i--) 683 | { 684 | data->payload[data->payload_len + i] = tuple % 10 + '0'; 685 | tuple /= 10; 686 | } 687 | 688 | data->payload_len += digits; 689 | return 0; 690 | } 691 | 692 | static quirc_decode_error_t decode_numeric(struct quirc_data *data, 693 | struct datastream *ds) 694 | { 695 | int bits = 14; 696 | int count; 697 | 698 | if (data->version < 10) 699 | bits = 10; 700 | else if (data->version < 27) 701 | bits = 12; 702 | 703 | count = take_bits(ds, bits); 704 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 705 | return QUIRC_ERROR_DATA_OVERFLOW; 706 | 707 | while (count >= 3) 708 | { 709 | if (numeric_tuple(data, ds, 10, 3) < 0) 710 | return QUIRC_ERROR_DATA_UNDERFLOW; 711 | count -= 3; 712 | } 713 | 714 | if (count >= 2) 715 | { 716 | if (numeric_tuple(data, ds, 7, 2) < 0) 717 | return QUIRC_ERROR_DATA_UNDERFLOW; 718 | count -= 2; 719 | } 720 | 721 | if (count) 722 | { 723 | if (numeric_tuple(data, ds, 4, 1) < 0) 724 | return QUIRC_ERROR_DATA_UNDERFLOW; 725 | count--; 726 | } 727 | 728 | return QUIRC_SUCCESS; 729 | } 730 | 731 | static int alpha_tuple(struct quirc_data *data, 732 | struct datastream *ds, 733 | int bits, int digits) 734 | { 735 | int tuple; 736 | int i; 737 | 738 | if (bits_remaining(ds) < bits) 739 | return -1; 740 | 741 | tuple = take_bits(ds, bits); 742 | 743 | for (i = 0; i < digits; i++) 744 | { 745 | static const char *alpha_map = 746 | "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; 747 | 748 | data->payload[data->payload_len + digits - i - 1] = 749 | alpha_map[tuple % 45]; 750 | tuple /= 45; 751 | } 752 | 753 | data->payload_len += digits; 754 | return 0; 755 | } 756 | 757 | static quirc_decode_error_t decode_alpha(struct quirc_data *data, 758 | struct datastream *ds) 759 | { 760 | int bits = 13; 761 | int count; 762 | 763 | if (data->version < 10) 764 | bits = 9; 765 | else if (data->version < 27) 766 | bits = 11; 767 | 768 | count = take_bits(ds, bits); 769 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 770 | return QUIRC_ERROR_DATA_OVERFLOW; 771 | 772 | while (count >= 2) 773 | { 774 | if (alpha_tuple(data, ds, 11, 2) < 0) 775 | return QUIRC_ERROR_DATA_UNDERFLOW; 776 | count -= 2; 777 | } 778 | 779 | if (count) 780 | { 781 | if (alpha_tuple(data, ds, 6, 1) < 0) 782 | return QUIRC_ERROR_DATA_UNDERFLOW; 783 | count--; 784 | } 785 | 786 | return QUIRC_SUCCESS; 787 | } 788 | 789 | static quirc_decode_error_t decode_byte(struct quirc_data *data, 790 | struct datastream *ds) 791 | { 792 | int bits = 16; 793 | int count; 794 | int i; 795 | 796 | if (data->version < 10) 797 | bits = 8; 798 | 799 | count = take_bits(ds, bits); 800 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 801 | return QUIRC_ERROR_DATA_OVERFLOW; 802 | if (bits_remaining(ds) < count * 8) 803 | return QUIRC_ERROR_DATA_UNDERFLOW; 804 | 805 | for (i = 0; i < count; i++) 806 | data->payload[data->payload_len++] = take_bits(ds, 8); 807 | 808 | return QUIRC_SUCCESS; 809 | } 810 | 811 | static quirc_decode_error_t decode_kanji(struct quirc_data *data, 812 | struct datastream *ds) 813 | { 814 | int bits = 12; 815 | int count; 816 | int i; 817 | 818 | if (data->version < 10) 819 | bits = 8; 820 | else if (data->version < 27) 821 | bits = 10; 822 | 823 | count = take_bits(ds, bits); 824 | if (data->payload_len + count * 2 + 1 > QUIRC_MAX_PAYLOAD) 825 | return QUIRC_ERROR_DATA_OVERFLOW; 826 | if (bits_remaining(ds) < count * 13) 827 | return QUIRC_ERROR_DATA_UNDERFLOW; 828 | 829 | for (i = 0; i < count; i++) 830 | { 831 | int d = take_bits(ds, 13); 832 | int msB = d / 0xc0; 833 | int lsB = d % 0xc0; 834 | int intermediate = (msB << 8) | lsB; 835 | uint16_t sjw; 836 | 837 | if (intermediate + 0x8140 <= 0x9ffc) 838 | { 839 | /* bytes are in the range 0x8140 to 0x9FFC */ 840 | sjw = intermediate + 0x8140; 841 | } 842 | else 843 | { 844 | /* bytes are in the range 0xE040 to 0xEBBF */ 845 | sjw = intermediate + 0xc140; 846 | } 847 | 848 | data->payload[data->payload_len++] = sjw >> 8; 849 | data->payload[data->payload_len++] = sjw & 0xff; 850 | } 851 | 852 | return QUIRC_SUCCESS; 853 | } 854 | 855 | static quirc_decode_error_t decode_eci(struct quirc_data *data, 856 | struct datastream *ds) 857 | { 858 | if (bits_remaining(ds) < 8) 859 | return QUIRC_ERROR_DATA_UNDERFLOW; 860 | 861 | data->eci = take_bits(ds, 8); 862 | 863 | if ((data->eci & 0xc0) == 0x80) 864 | { 865 | if (bits_remaining(ds) < 8) 866 | return QUIRC_ERROR_DATA_UNDERFLOW; 867 | 868 | data->eci = (data->eci << 8) | take_bits(ds, 8); 869 | } 870 | else if ((data->eci & 0xe0) == 0xc0) 871 | { 872 | if (bits_remaining(ds) < 16) 873 | return QUIRC_ERROR_DATA_UNDERFLOW; 874 | 875 | data->eci = (data->eci << 16) | take_bits(ds, 16); 876 | } 877 | 878 | return QUIRC_SUCCESS; 879 | } 880 | 881 | static quirc_decode_error_t decode_payload(struct quirc_data *data, 882 | struct datastream *ds) 883 | { 884 | while (bits_remaining(ds) >= 4) 885 | { 886 | quirc_decode_error_t err = QUIRC_SUCCESS; 887 | int type = take_bits(ds, 4); 888 | 889 | switch (type) 890 | { 891 | case QUIRC_DATA_TYPE_NUMERIC: 892 | err = decode_numeric(data, ds); 893 | break; 894 | 895 | case QUIRC_DATA_TYPE_ALPHA: 896 | err = decode_alpha(data, ds); 897 | break; 898 | 899 | case QUIRC_DATA_TYPE_BYTE: 900 | err = decode_byte(data, ds); 901 | break; 902 | 903 | case QUIRC_DATA_TYPE_KANJI: 904 | err = decode_kanji(data, ds); 905 | break; 906 | 907 | case 7: 908 | err = decode_eci(data, ds); 909 | break; 910 | 911 | default: 912 | goto done; 913 | } 914 | 915 | if (err) 916 | return err; 917 | 918 | if (!(type & (type - 1)) && (type > data->data_type)) 919 | data->data_type = type; 920 | } 921 | 922 | done: 923 | 924 | /* Add nul terminator to all payloads */ 925 | if (data->payload_len >= sizeof(data->payload)) 926 | data->payload_len--; 927 | data->payload[data->payload_len] = 0; 928 | 929 | return QUIRC_SUCCESS; 930 | } 931 | 932 | quirc_decode_error_t quirc_decode(const struct quirc_code *code, 933 | struct quirc_data *data) 934 | { 935 | quirc_decode_error_t err; 936 | struct datastream *ds = ps_malloc(sizeof(struct datastream)); 937 | 938 | if ((code->size - 17) % 4) 939 | { 940 | free(ds); 941 | return QUIRC_ERROR_INVALID_GRID_SIZE; 942 | } 943 | 944 | memset(data, 0, sizeof(*data)); 945 | memset(ds, 0, sizeof(*ds)); 946 | 947 | data->version = (code->size - 17) / 4; 948 | 949 | if (data->version < 1 || 950 | data->version > QUIRC_MAX_VERSION) 951 | { 952 | free(ds); 953 | return QUIRC_ERROR_INVALID_VERSION; 954 | } 955 | 956 | /* Read format information -- try both locations */ 957 | err = read_format(code, data, 0); 958 | if (err) 959 | err = read_format(code, data, 1); 960 | if (err) 961 | { 962 | free(ds); 963 | return err; 964 | } 965 | 966 | read_data(code, data, ds); 967 | err = codestream_ecc(data, ds); 968 | if (err) 969 | { 970 | free(ds); 971 | return err; 972 | } 973 | 974 | err = decode_payload(data, ds); 975 | if (err) 976 | { 977 | free(ds); 978 | return err; 979 | } 980 | 981 | free(ds); 982 | return QUIRC_SUCCESS; 983 | } -------------------------------------------------------------------------------- /src/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 | 22 | #include "openmv/fmath.h" 23 | #include "openmv/collections.h" 24 | #include "quirc_internal.h" 25 | 26 | /************************************************************************ 27 | * Linear algebra routines 28 | */ 29 | 30 | static int line_intersect(const struct quirc_point *p0, 31 | const struct quirc_point *p1, 32 | const struct quirc_point *q0, 33 | const struct quirc_point *q1, 34 | struct quirc_point *r) 35 | { 36 | /* (a, b) is perpendicular to line p */ 37 | int a = -(p1->y - p0->y); 38 | int b = p1->x - p0->x; 39 | 40 | /* (c, d) is perpendicular to line q */ 41 | int c = -(q1->y - q0->y); 42 | int d = q1->x - q0->x; 43 | 44 | /* e and f are dot products of the respective vectors with p and q */ 45 | int e = a * p1->x + b * p1->y; 46 | int f = c * q1->x + d * q1->y; 47 | 48 | /* Now we need to solve: 49 | * [a b] [rx] [e] 50 | * [c d] [ry] = [f] 51 | * 52 | * We do this by inverting the matrix and applying it to (e, f): 53 | * [ d -b] [e] [rx] 54 | * 1/det [-c a] [f] = [ry] 55 | */ 56 | int det = (a * d) - (b * c); 57 | 58 | if (!det) 59 | return 0; 60 | 61 | r->x = (d * e - b * f) / det; 62 | r->y = (-c * e + a * f) / det; 63 | 64 | return 1; 65 | } 66 | 67 | static void perspective_setup(float *c, 68 | const struct quirc_point *rect, 69 | float w, float h) 70 | { 71 | float x0 = rect[0].x; 72 | float y0 = rect[0].y; 73 | float x1 = rect[1].x; 74 | float y1 = rect[1].y; 75 | float x2 = rect[2].x; 76 | float y2 = rect[2].y; 77 | float x3 = rect[3].x; 78 | float y3 = rect[3].y; 79 | 80 | float wden = w * (x2 * y3 - x3 * y2 + (x3 - x2) * y1 + x1 * (y2 - y3)); 81 | float hden = h * (x2 * y3 + x1 * (y2 - y3) - x3 * y2 + (x3 - x2) * y1); 82 | 83 | c[0] = (x1 * (x2 * y3 - x3 * y2) + x0 * (-x2 * y3 + x3 * y2 + (x2 - x3) * y1) + 84 | x1 * (x3 - x2) * y0) / 85 | wden; 86 | c[1] = -(x0 * (x2 * y3 + x1 * (y2 - y3) - x2 * y1) - x1 * x3 * y2 + x2 * x3 * y1 + (x1 * x3 - x2 * x3) * y0) / hden; 87 | c[2] = x0; 88 | c[3] = (y0 * (x1 * (y3 - y2) - x2 * y3 + x3 * y2) + y1 * (x2 * y3 - x3 * y2) + 89 | x0 * y1 * (y2 - y3)) / 90 | wden; 91 | c[4] = (x0 * (y1 * y3 - y2 * y3) + x1 * y2 * y3 - x2 * y1 * y3 + 92 | y0 * (x3 * y2 - x1 * y2 + (x2 - x3) * y1)) / 93 | hden; 94 | c[5] = y0; 95 | c[6] = (x1 * (y3 - y2) + x0 * (y2 - y3) + (x2 - x3) * y1 + (x3 - x2) * y0) / wden; 96 | c[7] = (-x2 * y3 + x1 * y3 + x3 * y2 + x0 * (y1 - y2) - x3 * y1 + (x2 - x1) * y0) / 97 | hden; 98 | } 99 | 100 | static void perspective_map(const float *c, 101 | float u, float v, struct quirc_point *ret) 102 | { 103 | float den = c[6] * u + c[7] * v + 1.0; 104 | float x = (c[0] * u + c[1] * v + c[2]) / den; 105 | float y = (c[3] * u + c[4] * v + c[5]) / den; 106 | 107 | ret->x = fast_roundf(x); 108 | ret->y = fast_roundf(y); 109 | } 110 | 111 | static void perspective_unmap(const float *c, 112 | const struct quirc_point *in, 113 | float *u, float *v) 114 | { 115 | float x = in->x; 116 | float y = in->y; 117 | float den = -c[0] * c[7] * y + c[1] * c[6] * y + (c[3] * c[7] - c[4] * c[6]) * x + 118 | c[0] * c[4] - c[1] * c[3]; 119 | 120 | *u = -(c[1] * (y - c[5]) - c[2] * c[7] * y + (c[5] * c[7] - c[4]) * x + c[2] * c[4]) / 121 | den; 122 | *v = (c[0] * (y - c[5]) - c[2] * c[6] * y + (c[5] * c[6] - c[3]) * x + c[2] * c[3]) / 123 | den; 124 | } 125 | 126 | /************************************************************************ 127 | * Span-based floodfill routine 128 | */ 129 | 130 | typedef void (*span_func_t)(void *user_data, int y, int left, int right); 131 | 132 | typedef struct xylf 133 | { 134 | int16_t x, y, l, r; 135 | } __attribute__((aligned(8))) 136 | xylf_t; 137 | 138 | //计算该区域的面积,from是像素颜色,to是区块标号,user_data是申请的区块结构体,func是计算面积的函数 139 | static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to, 140 | span_func_t func, void *user_data, 141 | int depth) 142 | { 143 | (void)depth; // unused 144 | 145 | lifo_t lifo; 146 | size_t lifo_len; 147 | lifo_alloc_all(&lifo, &lifo_len, sizeof(xylf_t)); 148 | //late in first out. 申请xylf_t的lifo,一次申请完,长度存储在lifo_len中 149 | 150 | for (;;) 151 | { 152 | int left = x; 153 | int right = x; 154 | int i; 155 | quirc_pixel_t *row = q->pixels + y * q->w; //行起始地址 156 | //查找左右边界 157 | while (left > 0 && row[left - 1] == from) 158 | left--; 159 | 160 | while (right < q->w - 1 && row[right + 1] == from) 161 | right++; 162 | 163 | /* Fill the extent 对应像素标记为区块号*/ 164 | for (i = left; i <= right; i++) 165 | row[i] = to; 166 | //累加区域内的像素点数作为面积 167 | if (func) 168 | func(user_data, y, left, right); 169 | 170 | for (;;) 171 | { 172 | if (lifo_size(&lifo) < lifo_len) 173 | { //栈中的数量 174 | /* Seed new flood-fills */ 175 | if (y > 0) 176 | { //查找上一行有没有在同一区域的点 177 | row = q->pixels + (y - 1) * q->w; 178 | 179 | bool recurse = false; 180 | for (i = left; i <= right; i++) 181 | if (row[i] == from) 182 | { //相同区域,则入栈原来的区块 183 | xylf_t context; 184 | context.x = x; 185 | context.y = y; 186 | context.l = left; 187 | context.r = right; 188 | lifo_enqueue(&lifo, &context); 189 | //mp_printf(&mp_plat_print, "#x=%x,y=%d;x1=%d,y1=%d\n",x,y,i,y-1); 190 | x = i; 191 | y = y - 1; 192 | recurse = true; 193 | break; 194 | } 195 | if (recurse) 196 | break; 197 | } 198 | //查找下一行有没有在同一区域的点 199 | if (y < q->h - 1) 200 | { 201 | row = q->pixels + (y + 1) * q->w; 202 | 203 | bool recurse = false; 204 | for (i = left; i <= right; i++) 205 | if (row[i] == from) 206 | { 207 | xylf_t context; 208 | context.x = x; 209 | context.y = y; 210 | context.l = left; 211 | context.r = right; 212 | lifo_enqueue(&lifo, &context); 213 | //mp_printf(&mp_plat_print, "#x=%x,y=%d;x1=%d,y1=%d\n",x,y,i,y+1); 214 | x = i; 215 | y = y + 1; 216 | recurse = true; 217 | break; 218 | } 219 | if (recurse) 220 | break; 221 | } 222 | } 223 | 224 | if (!lifo_size(&lifo)) 225 | { 226 | lifo_free(&lifo); //如果最起始为止就没找到,那么返回 227 | return; 228 | } 229 | //本次迭代,往上,往下找边界(相同颜色像素点),直到找不到为止 230 | //找到边界后,出栈上层像素点,回退回去 231 | xylf_t context; 232 | lifo_dequeue(&lifo, &context); //这里存疑,如果都没有的话,dequeue就会反向溢出吧。。 233 | x = context.x; 234 | y = context.y; 235 | left = context.l; 236 | right = context.r; 237 | //mp_printf(&mp_plat_print, "#deq: x=%x,y=%d\n",x,y); 238 | } //找到相同from,break到这外面 239 | } 240 | } 241 | 242 | /************************************************************************ 243 | * Adaptive thresholding 244 | */ 245 | 246 | #define THRESHOLD_S_MIN 1 247 | #define THRESHOLD_S_DEN 8 248 | #define THRESHOLD_T 5 249 | 250 | static void threshold(struct quirc *q) 251 | { 252 | int x, y; 253 | int avg_w = 0; 254 | int avg_u = 0; 255 | int threshold_s = q->w / THRESHOLD_S_DEN; 256 | quirc_pixel_t *row = q->pixels; 257 | 258 | /* 259 | * Ensure a sane, non-zero value for threshold_s. 260 | * 261 | * threshold_s can be zero if the image width is small. We need to avoid 262 | * SIGFPE as it will be used as divisor. 263 | */ 264 | if (threshold_s < THRESHOLD_S_MIN) 265 | threshold_s = THRESHOLD_S_MIN; 266 | 267 | for (y = 0; y < q->h; y++) 268 | { 269 | int row_average[q->w]; 270 | 271 | memset(row_average, 0, sizeof(row_average)); 272 | 273 | for (x = 0; x < q->w; x++) 274 | { 275 | int w, u; 276 | 277 | if (y & 1) 278 | { 279 | w = x; 280 | u = q->w - 1 - x; 281 | } 282 | else 283 | { 284 | w = q->w - 1 - x; 285 | u = x; 286 | } 287 | 288 | avg_w = (avg_w * (threshold_s - 1)) / 289 | threshold_s + 290 | row[w]; 291 | avg_u = (avg_u * (threshold_s - 1)) / 292 | threshold_s + 293 | row[u]; 294 | 295 | row_average[w] += avg_w; 296 | row_average[u] += avg_u; 297 | } 298 | 299 | for (x = 0; x < q->w; x++) 300 | { 301 | if (row[x] < row_average[x] * 302 | (100 - THRESHOLD_T) / (200 * threshold_s)) 303 | row[x] = QUIRC_PIXEL_BLACK; 304 | else 305 | row[x] = QUIRC_PIXEL_WHITE; 306 | } 307 | 308 | row += q->w; 309 | } 310 | } 311 | 312 | static void area_count(void *user_data, int y, int left, int right) 313 | { 314 | ((struct quirc_region *)user_data)->count += right - left + 1; 315 | } 316 | 317 | static int region_code(struct quirc *q, int x, int y) 318 | { //region指的是QRcode的区域,成员为区域的坐标,像素面积,是否顶点 319 | int pixel; 320 | struct quirc_region *box; 321 | int region; 322 | 323 | if (x < 0 || y < 0 || x >= q->w || y >= q->h) 324 | return -1; 325 | 326 | pixel = q->pixels[y * q->w + x]; 327 | //预先判断非正常的像素情况,退出 328 | if (pixel >= QUIRC_PIXEL_REGION) 329 | return pixel; 330 | 331 | if (pixel == QUIRC_PIXEL_WHITE) 332 | return -1; 333 | 334 | if (q->num_regions >= QUIRC_MAX_REGIONS) 335 | return -1; 336 | //新建一个区域 337 | region = q->num_regions; 338 | box = &q->regions[q->num_regions++]; 339 | 340 | memset(box, 0, sizeof(*box)); 341 | 342 | box->seed.x = x; 343 | box->seed.y = y; 344 | box->capstone = -1; 345 | //计算该区域的面积 346 | flood_fill_seed(q, x, y, pixel, region, area_count, box, 0); 347 | 348 | return region; 349 | } 350 | 351 | struct polygon_score_data 352 | { 353 | struct quirc_point ref; 354 | 355 | int scores[4]; 356 | struct quirc_point *corners; 357 | } __attribute__((aligned(8))); 358 | 359 | static void find_one_corner(void *user_data, int y, int left, int right) 360 | { 361 | struct polygon_score_data *psd = 362 | (struct polygon_score_data *)user_data; 363 | int xs[2] = {left, right}; 364 | int dy = y - psd->ref.y; 365 | int i; 366 | 367 | for (i = 0; i < 2; i++) 368 | { 369 | int dx = xs[i] - psd->ref.x; 370 | int d = dx * dx + dy * dy; 371 | 372 | if (d > psd->scores[0]) 373 | { 374 | psd->scores[0] = d; 375 | psd->corners[0].x = xs[i]; 376 | psd->corners[0].y = y; 377 | } 378 | } 379 | } 380 | 381 | static void find_other_corners(void *user_data, int y, int left, int right) 382 | { 383 | struct polygon_score_data *psd = 384 | (struct polygon_score_data *)user_data; 385 | int xs[2] = {left, right}; 386 | int i; 387 | 388 | for (i = 0; i < 2; i++) 389 | { 390 | int up = xs[i] * psd->ref.x + y * psd->ref.y; 391 | int right = xs[i] * -psd->ref.y + y * psd->ref.x; 392 | int scores[4] = {up, right, -up, -right}; 393 | int j; 394 | 395 | for (j = 0; j < 4; j++) 396 | { 397 | if (scores[j] > psd->scores[j]) 398 | { 399 | psd->scores[j] = scores[j]; 400 | psd->corners[j].x = xs[i]; 401 | psd->corners[j].y = y; 402 | } 403 | } 404 | } 405 | } 406 | 407 | static void find_region_corners(struct quirc *q, 408 | int rcode, const struct quirc_point *ref, 409 | struct quirc_point *corners) 410 | { 411 | struct quirc_region *region = &q->regions[rcode]; 412 | struct polygon_score_data psd; 413 | int i; 414 | 415 | memset(&psd, 0, sizeof(psd)); 416 | psd.corners = corners; 417 | 418 | memcpy(&psd.ref, ref, sizeof(psd.ref)); 419 | psd.scores[0] = -1; 420 | flood_fill_seed(q, region->seed.x, region->seed.y, 421 | rcode, QUIRC_PIXEL_BLACK, 422 | find_one_corner, &psd, 0); 423 | 424 | psd.ref.x = psd.corners[0].x - psd.ref.x; 425 | psd.ref.y = psd.corners[0].y - psd.ref.y; 426 | 427 | for (i = 0; i < 4; i++) 428 | memcpy(&psd.corners[i], ®ion->seed, 429 | sizeof(psd.corners[i])); 430 | 431 | i = region->seed.x * psd.ref.x + region->seed.y * psd.ref.y; 432 | psd.scores[0] = i; 433 | psd.scores[2] = -i; 434 | i = region->seed.x * -psd.ref.y + region->seed.y * psd.ref.x; 435 | psd.scores[1] = i; 436 | psd.scores[3] = -i; 437 | 438 | flood_fill_seed(q, region->seed.x, region->seed.y, 439 | QUIRC_PIXEL_BLACK, rcode, 440 | find_other_corners, &psd, 0); 441 | } 442 | 443 | static void record_capstone(struct quirc *q, int ring, int stone) 444 | { 445 | struct quirc_region *stone_reg = &q->regions[stone]; 446 | struct quirc_region *ring_reg = &q->regions[ring]; 447 | struct quirc_capstone *capstone; 448 | int cs_index; 449 | 450 | if (q->num_capstones >= QUIRC_MAX_CAPSTONES) 451 | return; 452 | 453 | cs_index = q->num_capstones; 454 | capstone = &q->capstones[q->num_capstones++]; 455 | 456 | memset(capstone, 0, sizeof(*capstone)); 457 | 458 | capstone->qr_grid = -1; 459 | capstone->ring = ring; 460 | capstone->stone = stone; 461 | stone_reg->capstone = cs_index; 462 | ring_reg->capstone = cs_index; 463 | 464 | /* Find the corners of the ring */ 465 | find_region_corners(q, ring, &stone_reg->seed, capstone->corners); 466 | 467 | /* Set up the perspective transform and find the center */ 468 | perspective_setup(capstone->c, capstone->corners, 7.0, 7.0); 469 | perspective_map(capstone->c, 3.5, 3.5, &capstone->center); 470 | } 471 | 472 | static void test_capstone(struct quirc *q, int x, int y, int *pb) 473 | { 474 | int ring_right = region_code(q, x - pb[4], y); //x-pb[4]是标记环右边的左侧 475 | int stone = region_code(q, x - pb[4] - pb[3] - pb[2], y); //实心点左侧 476 | int ring_left = region_code(q, x - pb[4] - pb[3] - pb[2] - pb[1] - pb[0], y); //环左侧 477 | struct quirc_region *stone_reg; 478 | struct quirc_region *ring_reg; 479 | int ratio; 480 | //以下检测顶点标记是否符合规范,环称为ring,中间称为stone 481 | if (ring_left < 0 || ring_right < 0 || stone < 0) 482 | return; 483 | 484 | /* Left and ring of ring should be connected */ 485 | if (ring_left != ring_right) 486 | return; 487 | 488 | /* Ring should be disconnected from stone */ 489 | if (ring_left == stone) 490 | return; 491 | 492 | stone_reg = &q->regions[stone]; 493 | ring_reg = &q->regions[ring_left]; 494 | 495 | /* Already detected */ 496 | if (stone_reg->capstone >= 0 || ring_reg->capstone >= 0) 497 | return; 498 | 499 | /* Ratio should ideally be 37.5 中间实心点占面积比例应该在37.5%左右*/ 500 | ratio = stone_reg->count * 100 / ring_reg->count; 501 | if (ratio < 10 || ratio > 70) 502 | return; 503 | 504 | record_capstone(q, ring_left, stone); 505 | } 506 | 507 | static void finder_scan(struct quirc *q, int y) 508 | { 509 | quirc_pixel_t *row = q->pixels + y * q->w; 510 | int x; 511 | int last_color = 0; 512 | int run_length = 0; 513 | int run_count = 0; 514 | int pb[5]; //means QRcode's pixel width 515 | 516 | memset(pb, 0, sizeof(pb)); 517 | for (x = 0; x < q->w; x++) 518 | { 519 | int color = row[x] ? 1 : 0; 520 | 521 | if (x && color != last_color) 522 | { // color is different 523 | memmove(pb, pb + 1, sizeof(pb[0]) * 4); //left move in one data 524 | pb[4] = run_length; //run how many pix to get different color 525 | run_length = 0; 526 | run_count++; //get more than 5 time color jump 527 | 528 | if (!color && run_count >= 5) 529 | { // find the marker of QRcode(three corner's marker) 530 | static int check[5] = {1, 1, 3, 1, 1}; 531 | int avg, err; 532 | int i; 533 | int ok = 1; 534 | 535 | avg = (pb[0] + pb[1] + pb[3] + pb[4]) / 4; 536 | err = avg * 3 / 4; 537 | 538 | for (i = 0; i < 5; i++) 539 | if (pb[i] < check[i] * avg - err || 540 | pb[i] > check[i] * avg + err) 541 | ok = 0; 542 | 543 | if (ok) 544 | test_capstone(q, x, y, pb); 545 | } 546 | } 547 | 548 | run_length++; 549 | last_color = color; 550 | } 551 | } 552 | 553 | static void find_alignment_pattern(struct quirc *q, int index) 554 | { 555 | struct quirc_grid *qr = &q->grids[index]; 556 | struct quirc_capstone *c0 = &q->capstones[qr->caps[0]]; 557 | struct quirc_capstone *c2 = &q->capstones[qr->caps[2]]; 558 | struct quirc_point a; 559 | struct quirc_point b; 560 | struct quirc_point c; 561 | int size_estimate; 562 | int step_size = 1; 563 | int dir = 0; 564 | float u, v; 565 | 566 | /* Grab our previous estimate of the alignment pattern corner */ 567 | memcpy(&b, &qr->align, sizeof(b)); 568 | 569 | /* Guess another two corners of the alignment pattern so that we 570 | * can estimate its size. 571 | */ 572 | perspective_unmap(c0->c, &b, &u, &v); 573 | perspective_map(c0->c, u, v + 1.0, &a); 574 | perspective_unmap(c2->c, &b, &u, &v); 575 | perspective_map(c2->c, u + 1.0, v, &c); 576 | 577 | size_estimate = abs((a.x - b.x) * -(c.y - b.y) + 578 | (a.y - b.y) * (c.x - b.x)); 579 | 580 | /* Spiral outwards from the estimate point until we find something 581 | * roughly the right size. Don't look too far from the estimate 582 | * point. 583 | */ 584 | while (step_size * step_size < size_estimate * 100) 585 | { 586 | static const int dx_map[] = {1, 0, -1, 0}; 587 | static const int dy_map[] = {0, -1, 0, 1}; 588 | int i; 589 | 590 | for (i = 0; i < step_size; i++) 591 | { 592 | int code = region_code(q, b.x, b.y); 593 | 594 | if (code >= 0) 595 | { 596 | struct quirc_region *reg = &q->regions[code]; 597 | 598 | if (reg->count >= size_estimate / 2 && 599 | reg->count <= size_estimate * 2) 600 | { 601 | qr->align_region = code; 602 | return; 603 | } 604 | } 605 | 606 | b.x += dx_map[dir]; 607 | b.y += dy_map[dir]; 608 | } 609 | 610 | dir = (dir + 1) % 4; 611 | if (!(dir & 1)) 612 | step_size++; 613 | } 614 | } 615 | 616 | static void find_leftmost_to_line(void *user_data, int y, int left, int right) 617 | { 618 | struct polygon_score_data *psd = 619 | (struct polygon_score_data *)user_data; 620 | int xs[2] = {left, right}; 621 | int i; 622 | 623 | for (i = 0; i < 2; i++) 624 | { 625 | int d = -psd->ref.y * xs[i] + psd->ref.x * y; 626 | 627 | if (d < psd->scores[0]) 628 | { 629 | psd->scores[0] = d; 630 | psd->corners[0].x = xs[i]; 631 | psd->corners[0].y = y; 632 | } 633 | } 634 | } 635 | 636 | /* Do a Bresenham scan from one point to another and count the number 637 | * of black/white transitions. 638 | */ 639 | static int timing_scan(const struct quirc *q, 640 | const struct quirc_point *p0, 641 | const struct quirc_point *p1) 642 | { 643 | int n = p1->x - p0->x; 644 | int d = p1->y - p0->y; 645 | int x = p0->x; 646 | int y = p0->y; 647 | int *dom, *nondom; 648 | int dom_step; 649 | int nondom_step; 650 | int a = 0; 651 | int i; 652 | int run_length = 0; 653 | int count = 0; 654 | 655 | if (p0->x < 0 || p0->y < 0 || p0->x >= q->w || p0->y >= q->h) 656 | return -1; 657 | if (p1->x < 0 || p1->y < 0 || p1->x >= q->w || p1->y >= q->h) 658 | return -1; 659 | 660 | if (abs(n) > abs(d)) 661 | { 662 | int swap = n; 663 | 664 | n = d; 665 | d = swap; 666 | 667 | dom = &x; 668 | nondom = &y; 669 | } 670 | else 671 | { 672 | dom = &y; 673 | nondom = &x; 674 | } 675 | 676 | if (n < 0) 677 | { 678 | n = -n; 679 | nondom_step = -1; 680 | } 681 | else 682 | { 683 | nondom_step = 1; 684 | } 685 | 686 | if (d < 0) 687 | { 688 | d = -d; 689 | dom_step = -1; 690 | } 691 | else 692 | { 693 | dom_step = 1; 694 | } 695 | 696 | x = p0->x; 697 | y = p0->y; 698 | for (i = 0; i <= d; i++) 699 | { 700 | int pixel; 701 | 702 | if (y < 0 || y >= q->h || x < 0 || x >= q->w) 703 | break; 704 | 705 | pixel = q->pixels[y * q->w + x]; 706 | 707 | if (pixel) 708 | { 709 | if (run_length >= 2) 710 | count++; 711 | run_length = 0; 712 | } 713 | else 714 | { 715 | run_length++; 716 | } 717 | 718 | a += n; 719 | *dom += dom_step; 720 | if (a >= d) 721 | { 722 | *nondom += nondom_step; 723 | a -= d; 724 | } 725 | } 726 | 727 | return count; 728 | } 729 | 730 | /* Try the measure the timing pattern for a given QR code. This does 731 | * not require the global perspective to have been set up, but it 732 | * does require that the capstone corners have been set to their 733 | * canonical rotation. 734 | * 735 | * For each capstone, we find a point in the middle of the ring band 736 | * which is nearest the centre of the code. Using these points, we do 737 | * a horizontal and a vertical timing scan. 738 | */ 739 | static int measure_timing_pattern(struct quirc *q, int index) 740 | { 741 | struct quirc_grid *qr = &q->grids[index]; 742 | int i; 743 | int scan; 744 | int ver; 745 | int size; 746 | 747 | for (i = 0; i < 3; i++) 748 | { 749 | static const float us[] = {6.5, 6.5, 0.5}; 750 | static const float vs[] = {0.5, 6.5, 6.5}; 751 | struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; 752 | 753 | perspective_map(cap->c, us[i], vs[i], &qr->tpep[i]); 754 | } 755 | 756 | qr->hscan = timing_scan(q, &qr->tpep[1], &qr->tpep[2]); 757 | qr->vscan = timing_scan(q, &qr->tpep[1], &qr->tpep[0]); 758 | 759 | scan = qr->hscan; 760 | if (qr->vscan > scan) 761 | scan = qr->vscan; 762 | 763 | /* If neither scan worked, we can't go any further. */ 764 | if (scan < 0) 765 | return -1; 766 | 767 | /* Choose the nearest allowable grid size */ 768 | size = scan * 2 + 13; 769 | ver = (size - 15) / 4; 770 | qr->grid_size = ver * 4 + 17; 771 | 772 | return 0; 773 | } 774 | 775 | /* Read a cell from a grid using the currently set perspective 776 | * transform. Returns +/- 1 for black/white, 0 for cells which are 777 | * out of image bounds. 778 | */ 779 | static int read_cell(const struct quirc *q, int index, int x, int y) 780 | { 781 | const struct quirc_grid *qr = &q->grids[index]; 782 | struct quirc_point p; 783 | 784 | perspective_map(qr->c, x + 0.5, y + 0.5, &p); 785 | if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w) 786 | return 0; 787 | 788 | return q->pixels[p.y * q->w + p.x] ? 1 : -1; 789 | } 790 | 791 | static int fitness_cell(const struct quirc *q, int index, int x, int y) 792 | { 793 | const struct quirc_grid *qr = &q->grids[index]; 794 | int score = 0; 795 | int u, v; 796 | 797 | for (v = 0; v < 3; v++) 798 | for (u = 0; u < 3; u++) 799 | { 800 | static const float offsets[] = {0.3, 0.5, 0.7}; 801 | struct quirc_point p; 802 | 803 | perspective_map(qr->c, x + offsets[u], 804 | y + offsets[v], &p); 805 | if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w) 806 | continue; 807 | 808 | if (q->pixels[p.y * q->w + p.x]) 809 | score++; 810 | else 811 | score--; 812 | } 813 | 814 | return score; 815 | } 816 | 817 | static int fitness_ring(const struct quirc *q, int index, int cx, int cy, 818 | int radius) 819 | { 820 | int i; 821 | int score = 0; 822 | 823 | for (i = 0; i < radius * 2; i++) 824 | { 825 | score += fitness_cell(q, index, cx - radius + i, cy - radius); 826 | score += fitness_cell(q, index, cx - radius, cy + radius - i); 827 | score += fitness_cell(q, index, cx + radius, cy - radius + i); 828 | score += fitness_cell(q, index, cx + radius - i, cy + radius); 829 | } 830 | 831 | return score; 832 | } 833 | 834 | static int fitness_apat(const struct quirc *q, int index, int cx, int cy) 835 | { 836 | return fitness_cell(q, index, cx, cy) - 837 | fitness_ring(q, index, cx, cy, 1) + 838 | fitness_ring(q, index, cx, cy, 2); 839 | } 840 | 841 | static int fitness_capstone(const struct quirc *q, int index, int x, int y) 842 | { 843 | x += 3; 844 | y += 3; 845 | 846 | return fitness_cell(q, index, x, y) + 847 | fitness_ring(q, index, x, y, 1) - 848 | fitness_ring(q, index, x, y, 2) + 849 | fitness_ring(q, index, x, y, 3); 850 | } 851 | 852 | /* Compute a fitness score for the currently configured perspective 853 | * transform, using the features we expect to find by scanning the 854 | * grid. 855 | */ 856 | static int fitness_all(const struct quirc *q, int index) 857 | { 858 | const struct quirc_grid *qr = &q->grids[index]; 859 | int version = (qr->grid_size - 17) / 4; 860 | const struct quirc_version_info *info = &quirc_version_db[version]; 861 | int score = 0; 862 | int i, j; 863 | int ap_count; 864 | 865 | /* Check the timing pattern */ 866 | for (i = 0; i < qr->grid_size - 14; i++) 867 | { 868 | int expect = (i & 1) ? 1 : -1; 869 | 870 | score += fitness_cell(q, index, i + 7, 6) * expect; 871 | score += fitness_cell(q, index, 6, i + 7) * expect; 872 | } 873 | 874 | /* Check capstones */ 875 | score += fitness_capstone(q, index, 0, 0); 876 | score += fitness_capstone(q, index, qr->grid_size - 7, 0); 877 | score += fitness_capstone(q, index, 0, qr->grid_size - 7); 878 | 879 | if (version < 0 || version > QUIRC_MAX_VERSION) 880 | return score; 881 | 882 | /* Check alignment patterns */ 883 | ap_count = 0; 884 | while ((ap_count < QUIRC_MAX_ALIGNMENT) && info->apat[ap_count]) 885 | ap_count++; 886 | 887 | for (i = 1; i + 1 < ap_count; i++) 888 | { 889 | score += fitness_apat(q, index, 6, info->apat[i]); 890 | score += fitness_apat(q, index, info->apat[i], 6); 891 | } 892 | 893 | for (i = 1; i < ap_count; i++) 894 | for (j = 1; j < ap_count; j++) 895 | score += fitness_apat(q, index, 896 | info->apat[i], info->apat[j]); 897 | //mp_printf(&mp_plat_print, "##score=%d\n",score); 898 | return score; 899 | } 900 | 901 | static void jiggle_perspective(struct quirc *q, int index) 902 | { 903 | struct quirc_grid *qr = &q->grids[index]; 904 | int best = fitness_all(q, index); 905 | int pass; 906 | float adjustments[8]; 907 | int i; 908 | 909 | for (i = 0; i < 8; i++) 910 | adjustments[i] = qr->c[i] * 0.02; 911 | 912 | for (pass = 0; pass < 5; pass++) 913 | { 914 | for (i = 0; i < 16; i++) 915 | { 916 | int j = i >> 1; 917 | int test; 918 | float old = qr->c[j]; 919 | float step = adjustments[j]; 920 | float new; 921 | 922 | if (i & 1) 923 | new = old + step; 924 | else 925 | new = old - step; 926 | 927 | qr->c[j] = new; 928 | test = fitness_all(q, index); 929 | 930 | if (test > best) 931 | best = test; 932 | else 933 | qr->c[j] = old; 934 | } 935 | 936 | for (i = 0; i < 8; i++) 937 | adjustments[i] *= 0.5; 938 | } 939 | } 940 | 941 | /* Once the capstones are in place and an alignment point has been 942 | * chosen, we call this function to set up a grid-reading perspective 943 | * transform. 944 | */ 945 | static void setup_qr_perspective(struct quirc *q, int index) 946 | { 947 | struct quirc_grid *qr = &q->grids[index]; 948 | struct quirc_point rect[4]; 949 | 950 | /* Set up the perspective map for reading the grid */ 951 | memcpy(&rect[0], &q->capstones[qr->caps[1]].corners[0], 952 | sizeof(rect[0])); 953 | memcpy(&rect[1], &q->capstones[qr->caps[2]].corners[0], 954 | sizeof(rect[0])); 955 | memcpy(&rect[2], &qr->align, sizeof(rect[0])); 956 | memcpy(&rect[3], &q->capstones[qr->caps[0]].corners[0], 957 | sizeof(rect[0])); 958 | perspective_setup(qr->c, rect, qr->grid_size - 7, qr->grid_size - 7); 959 | 960 | jiggle_perspective(q, index); 961 | } 962 | 963 | /* Rotate the capstone with so that corner 0 is the leftmost with respect 964 | * to the given reference line. 965 | */ 966 | static void rotate_capstone(struct quirc_capstone *cap, 967 | const struct quirc_point *h0, 968 | const struct quirc_point *hd) 969 | { 970 | struct quirc_point copy[4]; 971 | int j; 972 | int best = 0; 973 | int best_score = 0; 974 | 975 | for (j = 0; j < 4; j++) 976 | { 977 | struct quirc_point *p = &cap->corners[j]; 978 | int score = (p->x - h0->x) * -hd->y + 979 | (p->y - h0->y) * hd->x; 980 | 981 | if (!j || score < best_score) 982 | { 983 | best = j; 984 | best_score = score; 985 | } 986 | } 987 | 988 | /* Rotate the capstone */ 989 | for (j = 0; j < 4; j++) 990 | memcpy(©[j], &cap->corners[(j + best) % 4], 991 | sizeof(copy[j])); 992 | memcpy(cap->corners, copy, sizeof(cap->corners)); 993 | perspective_setup(cap->c, cap->corners, 7.0, 7.0); 994 | } 995 | 996 | static void record_qr_grid(struct quirc *q, int a, int b, int c) 997 | { 998 | struct quirc_point h0, hd; 999 | int i; 1000 | int qr_index; 1001 | struct quirc_grid *qr; 1002 | 1003 | if (q->num_grids >= QUIRC_MAX_GRIDS) 1004 | return; 1005 | 1006 | /* Construct the hypotenuse line from A to C. B should be to 1007 | * the left of this line. 1008 | */ 1009 | memcpy(&h0, &q->capstones[a].center, sizeof(h0)); 1010 | hd.x = q->capstones[c].center.x - q->capstones[a].center.x; 1011 | hd.y = q->capstones[c].center.y - q->capstones[a].center.y; 1012 | 1013 | /* Make sure A-B-C is clockwise */ 1014 | if ((q->capstones[b].center.x - h0.x) * -hd.y + 1015 | (q->capstones[b].center.y - h0.y) * hd.x > 1016 | 0) 1017 | { 1018 | int swap = a; 1019 | 1020 | a = c; 1021 | c = swap; 1022 | hd.x = -hd.x; 1023 | hd.y = -hd.y; 1024 | } 1025 | 1026 | /* Record the grid and its components */ 1027 | qr_index = q->num_grids; 1028 | qr = &q->grids[q->num_grids++]; 1029 | 1030 | memset(qr, 0, sizeof(*qr)); 1031 | qr->caps[0] = a; 1032 | qr->caps[1] = b; 1033 | qr->caps[2] = c; 1034 | qr->align_region = -1; 1035 | 1036 | /* Rotate each capstone so that corner 0 is top-left with respect 1037 | * to the grid. 1038 | */ 1039 | for (i = 0; i < 3; i++) 1040 | { 1041 | struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; 1042 | 1043 | rotate_capstone(cap, &h0, &hd); 1044 | cap->qr_grid = qr_index; 1045 | } 1046 | 1047 | /* Check the timing pattern. This doesn't require a perspective 1048 | * transform. 1049 | */ 1050 | if (measure_timing_pattern(q, qr_index) < 0) 1051 | goto fail; 1052 | 1053 | /* Make an estimate based for the alignment pattern based on extending 1054 | * lines from capstones A and C. 1055 | */ 1056 | if (!line_intersect(&q->capstones[a].corners[0], 1057 | &q->capstones[a].corners[1], 1058 | &q->capstones[c].corners[0], 1059 | &q->capstones[c].corners[3], 1060 | &qr->align)) 1061 | goto fail; 1062 | 1063 | /* On V2+ grids, we should use the alignment pattern. */ 1064 | if (qr->grid_size > 21) 1065 | { 1066 | /* Try to find the actual location of the alignment pattern. */ 1067 | find_alignment_pattern(q, qr_index); 1068 | 1069 | /* Find the point of the alignment pattern closest to the 1070 | * top-left of the QR grid. 1071 | */ 1072 | if (qr->align_region >= 0) 1073 | { 1074 | struct polygon_score_data psd; 1075 | struct quirc_region *reg = 1076 | &q->regions[qr->align_region]; 1077 | 1078 | /* Start from some point inside the alignment pattern */ 1079 | memcpy(&qr->align, ®->seed, sizeof(qr->align)); 1080 | 1081 | memcpy(&psd.ref, &hd, sizeof(psd.ref)); 1082 | psd.corners = &qr->align; 1083 | psd.scores[0] = -hd.y * qr->align.x + 1084 | hd.x * qr->align.y; 1085 | 1086 | flood_fill_seed(q, reg->seed.x, reg->seed.y, 1087 | qr->align_region, QUIRC_PIXEL_BLACK, 1088 | NULL, NULL, 0); 1089 | flood_fill_seed(q, reg->seed.x, reg->seed.y, 1090 | QUIRC_PIXEL_BLACK, qr->align_region, 1091 | find_leftmost_to_line, &psd, 0); 1092 | } 1093 | } 1094 | 1095 | setup_qr_perspective(q, qr_index); 1096 | return; 1097 | 1098 | fail: 1099 | /* We've been unable to complete setup for this grid. Undo what we've 1100 | * recorded and pretend it never happened. 1101 | */ 1102 | for (i = 0; i < 3; i++) 1103 | q->capstones[qr->caps[i]].qr_grid = -1; 1104 | q->num_grids--; 1105 | } 1106 | 1107 | struct neighbour 1108 | { 1109 | int index; 1110 | float distance; 1111 | } __attribute__((aligned(8))); 1112 | 1113 | struct neighbour_list 1114 | { 1115 | struct neighbour n[QUIRC_MAX_CAPSTONES]; 1116 | int count; 1117 | } __attribute__((aligned(8))); 1118 | 1119 | static void test_neighbours(struct quirc *q, int i, 1120 | const struct neighbour_list *hlist, 1121 | const struct neighbour_list *vlist) 1122 | { 1123 | int j, k; 1124 | float best_score = 0.0; 1125 | int best_h = -1, best_v = -1; 1126 | 1127 | /* Test each possible grouping */ 1128 | for (j = 0; j < hlist->count; j++) 1129 | for (k = 0; k < vlist->count; k++) 1130 | { 1131 | const struct neighbour *hn = &hlist->n[j]; 1132 | const struct neighbour *vn = &vlist->n[k]; 1133 | float score = fast_fabsf(1.0 - hn->distance / vn->distance); 1134 | 1135 | if (score > 2.5) 1136 | continue; 1137 | 1138 | if (best_h < 0 || score < best_score) 1139 | { 1140 | best_h = hn->index; 1141 | best_v = vn->index; 1142 | best_score = score; 1143 | } 1144 | } 1145 | 1146 | if (best_h < 0 || best_v < 0) 1147 | return; 1148 | 1149 | record_qr_grid(q, best_h, i, best_v); 1150 | } 1151 | 1152 | static void test_grouping(struct quirc *q, int i) 1153 | { 1154 | struct quirc_capstone *c1 = &q->capstones[i]; 1155 | int j; 1156 | struct neighbour_list hlist; 1157 | struct neighbour_list vlist; 1158 | 1159 | if (c1->qr_grid >= 0) 1160 | return; 1161 | 1162 | hlist.count = 0; 1163 | vlist.count = 0; 1164 | 1165 | /* Look for potential neighbours by examining the relative gradients 1166 | * from this capstone to others. 1167 | */ 1168 | for (j = 0; j < q->num_capstones; j++) 1169 | { 1170 | struct quirc_capstone *c2 = &q->capstones[j]; 1171 | float u, v; 1172 | 1173 | if (i == j || c2->qr_grid >= 0) 1174 | continue; 1175 | 1176 | perspective_unmap(c1->c, &c2->center, &u, &v); 1177 | 1178 | u = fast_fabsf(u - 3.5); 1179 | v = fast_fabsf(v - 3.5); 1180 | 1181 | if (u < 0.2 * v) 1182 | { 1183 | struct neighbour *n = &hlist.n[hlist.count++]; 1184 | 1185 | n->index = j; 1186 | n->distance = v; 1187 | } 1188 | 1189 | if (v < 0.2 * u) 1190 | { 1191 | struct neighbour *n = &vlist.n[vlist.count++]; 1192 | 1193 | n->index = j; 1194 | n->distance = u; 1195 | } 1196 | } 1197 | 1198 | if (!(hlist.count && vlist.count)) 1199 | return; 1200 | 1201 | test_neighbours(q, i, &hlist, &vlist); 1202 | } 1203 | 1204 | static void pixels_setup(struct quirc *q) 1205 | { 1206 | if (sizeof(*q->image) == sizeof(*q->pixels)) 1207 | { 1208 | q->pixels = (quirc_pixel_t *)q->image; 1209 | } 1210 | else 1211 | { 1212 | int x, y; 1213 | for (y = 0; y < q->h; y++) 1214 | { 1215 | for (x = 0; x < q->w; x++) 1216 | { 1217 | q->pixels[y * q->w + x] = q->image[y * q->w + x]; 1218 | } 1219 | } 1220 | } 1221 | } 1222 | 1223 | uint8_t *quirc_begin(struct quirc *q, int *w, int *h) 1224 | { 1225 | q->num_regions = QUIRC_PIXEL_REGION; 1226 | q->num_capstones = 0; 1227 | q->num_grids = 0; 1228 | 1229 | if (w) 1230 | *w = q->w; 1231 | if (h) 1232 | *h = q->h; 1233 | 1234 | return q->image; 1235 | } 1236 | 1237 | void quirc_end(struct quirc *q) 1238 | { 1239 | int i; 1240 | pixels_setup(q); 1241 | threshold(q); 1242 | 1243 | for (i = 0; i < q->h; i++) 1244 | { 1245 | finder_scan(q, i); 1246 | } 1247 | 1248 | for (i = 0; i < q->num_capstones; i++) 1249 | { 1250 | test_grouping(q, i); 1251 | } 1252 | } 1253 | 1254 | void quirc_extract(const struct quirc *q, int index, 1255 | struct quirc_code *code) 1256 | { 1257 | const struct quirc_grid *qr = &q->grids[index]; 1258 | int y; 1259 | int i = 0; 1260 | 1261 | if (index < 0 || index > q->num_grids) 1262 | return; 1263 | 1264 | memset(code, 0, sizeof(*code)); 1265 | 1266 | perspective_map(qr->c, 0.0, 0.0, &code->corners[0]); 1267 | perspective_map(qr->c, qr->grid_size, 0.0, &code->corners[1]); 1268 | perspective_map(qr->c, qr->grid_size, qr->grid_size, 1269 | &code->corners[2]); 1270 | perspective_map(qr->c, 0.0, qr->grid_size, &code->corners[3]); 1271 | 1272 | code->size = qr->grid_size; 1273 | 1274 | for (y = 0; y < qr->grid_size; y++) 1275 | { 1276 | int x; 1277 | 1278 | for (x = 0; x < qr->grid_size; x++) 1279 | { 1280 | if (read_cell(q, index, x, y) > 0) 1281 | code->cell_bitmap[i >> 3] |= (1 << (i & 7)); 1282 | 1283 | i++; 1284 | } 1285 | } 1286 | } -------------------------------------------------------------------------------- /src/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 | #include 21 | 22 | const char *quirc_version(void) 23 | { 24 | return "1.0"; 25 | } 26 | 27 | //static struct quirc _q; 28 | struct quirc *quirc_new(void) 29 | { 30 | struct quirc *q = ps_malloc(sizeof(*q)); 31 | 32 | if (!q) 33 | return NULL; 34 | 35 | memset(q, 0, sizeof(*q)); 36 | return q; 37 | } 38 | 39 | void quirc_destroy(struct quirc *q) 40 | { 41 | if (q->image) 42 | if (q->image) 43 | free(q->image); 44 | if (sizeof(*q->image) != sizeof(*q->pixels)) 45 | if (q->pixels) 46 | free(q->pixels); 47 | 48 | if (q) 49 | free(q); 50 | } 51 | 52 | //static quirc_pixel_t img_buf[320*240]; 53 | int quirc_resize(struct quirc *q, int w, int h) 54 | { 55 | if (q->image) 56 | { 57 | free(q->image); 58 | } 59 | uint8_t *new_image = ps_malloc(w * h); 60 | 61 | if (!new_image) 62 | return -1; 63 | 64 | if (sizeof(*q->image) != sizeof(*q->pixels)) 65 | { //should gray, 1==1 66 | size_t new_size = w * h * sizeof(quirc_pixel_t); 67 | if (q->pixels) 68 | free(q->pixels); 69 | quirc_pixel_t *new_pixels = ps_malloc(new_size); 70 | if (!new_pixels) 71 | { 72 | free(new_image); 73 | return -1; 74 | } 75 | q->pixels = new_pixels; 76 | } 77 | q->image = new_image; 78 | q->w = w; 79 | q->h = h; 80 | return 0; 81 | } 82 | 83 | int quirc_count(const struct quirc *q) 84 | { 85 | return q->num_grids; 86 | } 87 | 88 | static const char *const error_table[] = { 89 | [QUIRC_SUCCESS] = "Success", 90 | [QUIRC_ERROR_INVALID_GRID_SIZE] = "Invalid grid size", 91 | [QUIRC_ERROR_INVALID_VERSION] = "Invalid version", 92 | [QUIRC_ERROR_FORMAT_ECC] = "Format data ECC failure", 93 | [QUIRC_ERROR_DATA_ECC] = "ECC failure", 94 | [QUIRC_ERROR_UNKNOWN_DATA_TYPE] = "Unknown data type", 95 | [QUIRC_ERROR_DATA_OVERFLOW] = "Data overflow", 96 | [QUIRC_ERROR_DATA_UNDERFLOW] = "Data underflow"}; 97 | 98 | const char *quirc_strerror(quirc_decode_error_t err) 99 | { 100 | if (err >= 0 && err < sizeof(error_table) / sizeof(error_table[0])) 101 | return error_table[err]; 102 | 103 | return "Unknown error"; 104 | } 105 | -------------------------------------------------------------------------------- /src/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 | { 25 | #endif 26 | 27 | struct quirc; 28 | 29 | /* Obtain the library version string. */ 30 | const char *quirc_version(void); 31 | 32 | /* Construct a new QR-code recognizer. This function will return NULL 33 | * if sufficient memory could not be allocated. 34 | */ 35 | struct quirc *quirc_new(void); 36 | 37 | /* Destroy a QR-code recognizer. */ 38 | void quirc_destroy(struct quirc *q); 39 | 40 | /* Resize the QR-code recognizer. The size of an image must be 41 | * specified before codes can be analyzed. 42 | * 43 | * This function returns 0 on success, or -1 if sufficient memory could 44 | * not be allocated. 45 | */ 46 | int quirc_resize(struct quirc *q, int w, int h); 47 | 48 | /* These functions are used to process images for QR-code recognition. 49 | * quirc_begin() must first be called to obtain access to a buffer into 50 | * which the input image should be placed. Optionally, the current 51 | * width and height may be returned. 52 | * 53 | * After filling the buffer, quirc_end() should be called to process 54 | * the image for QR-code recognition. The locations and content of each 55 | * code may be obtained using accessor functions described below. 56 | */ 57 | uint8_t *quirc_begin(struct quirc *q, int *w, int *h); 58 | void quirc_end(struct quirc *q); 59 | 60 | /* This structure describes a location in the input image buffer. */ 61 | struct quirc_point 62 | { 63 | int x; 64 | int y; 65 | } __attribute__((aligned(8))); 66 | 67 | /* This enum describes the various decoder errors which may occur. */ 68 | typedef enum 69 | { 70 | QUIRC_SUCCESS = 0, 71 | QUIRC_ERROR_INVALID_GRID_SIZE, 72 | QUIRC_ERROR_INVALID_VERSION, 73 | QUIRC_ERROR_FORMAT_ECC, 74 | QUIRC_ERROR_DATA_ECC, 75 | QUIRC_ERROR_UNKNOWN_DATA_TYPE, 76 | QUIRC_ERROR_DATA_OVERFLOW, 77 | QUIRC_ERROR_DATA_UNDERFLOW 78 | } quirc_decode_error_t; 79 | 80 | /* Return a string error message for an error code. */ 81 | const char *quirc_strerror(quirc_decode_error_t err); 82 | 83 | /* Limits on the maximum size of QR-codes and their content. */ 84 | #define QUIRC_MAX_BITMAP 3917 85 | #define QUIRC_MAX_PAYLOAD 8896 86 | 87 | /* QR-code ECC types. */ 88 | #define QUIRC_ECC_LEVEL_M 0 89 | #define QUIRC_ECC_LEVEL_L 1 90 | #define QUIRC_ECC_LEVEL_H 2 91 | #define QUIRC_ECC_LEVEL_Q 3 92 | 93 | /* QR-code data types. */ 94 | #define QUIRC_DATA_TYPE_NUMERIC 1 95 | #define QUIRC_DATA_TYPE_ALPHA 2 96 | #define QUIRC_DATA_TYPE_BYTE 4 97 | #define QUIRC_DATA_TYPE_KANJI 8 98 | 99 | /* Common character encodings */ 100 | #define QUIRC_ECI_ISO_8859_1 1 101 | #define QUIRC_ECI_IBM437 2 102 | #define QUIRC_ECI_ISO_8859_2 4 103 | #define QUIRC_ECI_ISO_8859_3 5 104 | #define QUIRC_ECI_ISO_8859_4 6 105 | #define QUIRC_ECI_ISO_8859_5 7 106 | #define QUIRC_ECI_ISO_8859_6 8 107 | #define QUIRC_ECI_ISO_8859_7 9 108 | #define QUIRC_ECI_ISO_8859_8 10 109 | #define QUIRC_ECI_ISO_8859_9 11 110 | #define QUIRC_ECI_WINDOWS_874 13 111 | #define QUIRC_ECI_ISO_8859_13 15 112 | #define QUIRC_ECI_ISO_8859_15 17 113 | #define QUIRC_ECI_SHIFT_JIS 20 114 | #define QUIRC_ECI_UTF_8 26 115 | 116 | /* This structure is used to return information about detected QR codes 117 | * in the input image. 118 | */ 119 | struct quirc_code 120 | { 121 | /* The four corners of the QR-code, from top left, clockwise */ 122 | struct quirc_point corners[4]; 123 | 124 | /* The number of cells across in the QR-code. The cell bitmap 125 | * is a bitmask giving the actual values of cells. If the cell 126 | * at (x, y) is black, then the following bit is set: 127 | * 128 | * cell_bitmap[i >> 3] & (1 << (i & 7)) 129 | * 130 | * where i = (y * size) + x. 131 | */ 132 | int size; 133 | uint8_t cell_bitmap[QUIRC_MAX_BITMAP]; 134 | } __attribute__((aligned(8))); 135 | 136 | /* This structure holds the decoded QR-code data */ 137 | struct quirc_data 138 | { 139 | /* Various parameters of the QR-code. These can mostly be 140 | * ignored if you only care about the data. 141 | */ 142 | int version; 143 | int ecc_level; 144 | int mask; 145 | 146 | /* This field is the highest-valued data type found in the QR 147 | * code. 148 | */ 149 | int data_type; 150 | 151 | /* Data payload. For the Kanji datatype, payload is encoded as 152 | * Shift-JIS. For all other datatypes, payload is ASCII text. 153 | */ 154 | uint8_t payload[QUIRC_MAX_PAYLOAD]; 155 | int payload_len; 156 | 157 | /* ECI assignment number */ 158 | uint32_t eci; 159 | } __attribute__((aligned(8))); 160 | 161 | /* Return the number of QR-codes identified in the last processed 162 | * image. 163 | */ 164 | int quirc_count(const struct quirc *q); 165 | 166 | /* Extract the QR-code specified by the given index. */ 167 | void quirc_extract(const struct quirc *q, int index, 168 | struct quirc_code *code); 169 | 170 | /* Decode a QR-code, returning the payload data. */ 171 | quirc_decode_error_t quirc_decode(const struct quirc_code *code, 172 | struct quirc_data *data); 173 | 174 | #ifdef __cplusplus 175 | } 176 | #endif 177 | 178 | #endif -------------------------------------------------------------------------------- /src/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 | 30 | #define QUIRC_MAX_CAPSTONES 32 31 | #define QUIRC_MAX_GRIDS 8 32 | 33 | #define QUIRC_PERSPECTIVE_PARAMS 8 34 | 35 | #if QUIRC_MAX_REGIONS < UINT8_MAX 36 | typedef uint8_t quirc_pixel_t; 37 | #elif QUIRC_MAX_REGIONS < UINT16_MAX 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 | { 45 | struct quirc_point seed; 46 | int count; 47 | int capstone; 48 | } __attribute__((aligned(8))); 49 | 50 | struct quirc_capstone 51 | { 52 | int ring; 53 | int stone; 54 | 55 | struct quirc_point corners[4]; 56 | struct quirc_point center; 57 | float c[QUIRC_PERSPECTIVE_PARAMS]; 58 | 59 | int qr_grid; 60 | } __attribute__((aligned(8))); 61 | 62 | struct quirc_grid 63 | { 64 | /* Capstone indices */ 65 | int caps[3]; 66 | 67 | /* Alignment pattern region and corner */ 68 | int align_region; 69 | struct quirc_point align; 70 | 71 | /* Timing pattern endpoints */ 72 | struct quirc_point tpep[3]; 73 | int hscan; 74 | int vscan; 75 | 76 | /* Grid size and perspective transform */ 77 | int grid_size; 78 | float c[QUIRC_PERSPECTIVE_PARAMS]; 79 | } __attribute__((aligned(8))); 80 | 81 | struct quirc 82 | { 83 | uint8_t *image; 84 | quirc_pixel_t *pixels; 85 | int w; 86 | int h; 87 | 88 | int num_regions; 89 | struct quirc_region regions[QUIRC_MAX_REGIONS]; 90 | 91 | int num_capstones; 92 | struct quirc_capstone capstones[QUIRC_MAX_CAPSTONES]; 93 | 94 | int num_grids; 95 | struct quirc_grid grids[QUIRC_MAX_GRIDS]; 96 | } __attribute__((aligned(8))); 97 | 98 | /************************************************************************ 99 | * QR-code version information database 100 | */ 101 | 102 | #define QUIRC_MAX_VERSION 40 103 | #define QUIRC_MAX_ALIGNMENT 7 104 | 105 | struct quirc_rs_params 106 | { 107 | uint8_t bs; /* Small block size */ 108 | uint8_t dw; /* Small data words */ 109 | uint8_t ns; /* Number of small blocks */ 110 | } __attribute__((aligned(8))); 111 | 112 | struct quirc_version_info 113 | { 114 | uint16_t data_bytes; 115 | uint8_t apat[QUIRC_MAX_ALIGNMENT]; 116 | struct quirc_rs_params ecc[4]; 117 | } __attribute__((aligned(8))); 118 | 119 | extern const struct quirc_version_info quirc_version_db[QUIRC_MAX_VERSION + 1]; 120 | 121 | #endif -------------------------------------------------------------------------------- /src/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 | {/* Version 2 */ 30 | .data_bytes = 44, 31 | .apat = {6, 18, 0}, 32 | .ecc = {{.bs = 44, .dw = 28, .ns = 1}, {.bs = 44, .dw = 34, .ns = 1}, {.bs = 44, .dw = 16, .ns = 1}, {.bs = 44, .dw = 22, .ns = 1}}}, 33 | {/* Version 3 */ 34 | .data_bytes = 70, 35 | .apat = {6, 22, 0}, 36 | .ecc = {{.bs = 70, .dw = 44, .ns = 1}, {.bs = 70, .dw = 55, .ns = 1}, {.bs = 35, .dw = 13, .ns = 2}, {.bs = 35, .dw = 17, .ns = 2}}}, 37 | {/* Version 4 */ 38 | .data_bytes = 100, 39 | .apat = {6, 26, 0}, 40 | .ecc = {{.bs = 50, .dw = 32, .ns = 2}, {.bs = 100, .dw = 80, .ns = 1}, {.bs = 25, .dw = 9, .ns = 4}, {.bs = 50, .dw = 24, .ns = 2}}}, 41 | {/* Version 5 */ 42 | .data_bytes = 134, 43 | .apat = {6, 30, 0}, 44 | .ecc = {{.bs = 67, .dw = 43, .ns = 2}, {.bs = 134, .dw = 108, .ns = 1}, {.bs = 33, .dw = 11, .ns = 2}, {.bs = 33, .dw = 15, .ns = 2}}}, 45 | {/* Version 6 */ 46 | .data_bytes = 172, 47 | .apat = {6, 34, 0}, 48 | .ecc = {{.bs = 43, .dw = 27, .ns = 4}, {.bs = 86, .dw = 68, .ns = 2}, {.bs = 43, .dw = 15, .ns = 4}, {.bs = 43, .dw = 19, .ns = 4}}}, 49 | {/* Version 7 */ 50 | .data_bytes = 196, 51 | .apat = {6, 22, 38, 0}, 52 | .ecc = {{.bs = 49, .dw = 31, .ns = 4}, {.bs = 98, .dw = 78, .ns = 2}, {.bs = 39, .dw = 13, .ns = 4}, {.bs = 32, .dw = 14, .ns = 2}}}, 53 | {/* Version 8 */ 54 | .data_bytes = 242, 55 | .apat = {6, 24, 42, 0}, 56 | .ecc = {{.bs = 60, .dw = 38, .ns = 2}, {.bs = 121, .dw = 97, .ns = 2}, {.bs = 40, .dw = 14, .ns = 4}, {.bs = 40, .dw = 18, .ns = 4}}}, 57 | {/* Version 9 */ 58 | .data_bytes = 292, 59 | .apat = {6, 26, 46, 0}, 60 | .ecc = {{.bs = 58, .dw = 36, .ns = 3}, {.bs = 146, .dw = 116, .ns = 2}, {.bs = 36, .dw = 12, .ns = 4}, {.bs = 36, .dw = 16, .ns = 4}}}, 61 | {/* Version 10 */ 62 | .data_bytes = 346, 63 | .apat = {6, 28, 50, 0}, 64 | .ecc = {{.bs = 69, .dw = 43, .ns = 4}, {.bs = 86, .dw = 68, .ns = 2}, {.bs = 43, .dw = 15, .ns = 6}, {.bs = 43, .dw = 19, .ns = 6}}}, 65 | {/* Version 11 */ 66 | .data_bytes = 404, 67 | .apat = {6, 30, 54, 0}, 68 | .ecc = {{.bs = 80, .dw = 50, .ns = 1}, {.bs = 101, .dw = 81, .ns = 4}, {.bs = 36, .dw = 12, .ns = 3}, {.bs = 50, .dw = 22, .ns = 4}}}, 69 | {/* Version 12 */ 70 | .data_bytes = 466, 71 | .apat = {6, 32, 58, 0}, 72 | .ecc = {{.bs = 58, .dw = 36, .ns = 6}, {.bs = 116, .dw = 92, .ns = 2}, {.bs = 42, .dw = 14, .ns = 7}, {.bs = 46, .dw = 20, .ns = 4}}}, 73 | {/* Version 13 */ 74 | .data_bytes = 532, 75 | .apat = {6, 34, 62, 0}, 76 | .ecc = {{.bs = 59, .dw = 37, .ns = 8}, {.bs = 133, .dw = 107, .ns = 4}, {.bs = 33, .dw = 11, .ns = 12}, {.bs = 44, .dw = 20, .ns = 8}}}, 77 | {/* Version 14 */ 78 | .data_bytes = 581, 79 | .apat = {6, 26, 46, 66, 0}, 80 | .ecc = {{.bs = 64, .dw = 40, .ns = 4}, {.bs = 145, .dw = 115, .ns = 3}, {.bs = 36, .dw = 12, .ns = 11}, {.bs = 36, .dw = 16, .ns = 11}}}, 81 | {/* Version 15 */ 82 | .data_bytes = 655, 83 | .apat = {6, 26, 48, 70, 0}, 84 | .ecc = {{.bs = 65, .dw = 41, .ns = 5}, {.bs = 109, .dw = 87, .ns = 5}, {.bs = 36, .dw = 12, .ns = 11}, {.bs = 54, .dw = 24, .ns = 5}}}, 85 | {/* Version 16 */ 86 | .data_bytes = 733, 87 | .apat = {6, 26, 50, 74, 0}, 88 | .ecc = {{.bs = 73, .dw = 45, .ns = 7}, {.bs = 122, .dw = 98, .ns = 5}, {.bs = 45, .dw = 15, .ns = 3}, {.bs = 43, .dw = 19, .ns = 15}}}, 89 | {/* Version 17 */ 90 | .data_bytes = 815, 91 | .apat = {6, 30, 54, 78, 0}, 92 | .ecc = {{.bs = 74, .dw = 46, .ns = 10}, {.bs = 135, .dw = 107, .ns = 1}, {.bs = 42, .dw = 14, .ns = 2}, {.bs = 50, .dw = 22, .ns = 1}}}, 93 | {/* Version 18 */ 94 | .data_bytes = 901, 95 | .apat = {6, 30, 56, 82, 0}, 96 | .ecc = {{.bs = 69, .dw = 43, .ns = 9}, {.bs = 150, .dw = 120, .ns = 5}, {.bs = 42, .dw = 14, .ns = 2}, {.bs = 50, .dw = 22, .ns = 17}}}, 97 | {/* Version 19 */ 98 | .data_bytes = 991, 99 | .apat = {6, 30, 58, 86, 0}, 100 | .ecc = {{.bs = 70, .dw = 44, .ns = 3}, {.bs = 141, .dw = 113, .ns = 3}, {.bs = 39, .dw = 13, .ns = 9}, {.bs = 47, .dw = 21, .ns = 17}}}, 101 | {/* Version 20 */ 102 | .data_bytes = 1085, 103 | .apat = {6, 34, 62, 90, 0}, 104 | .ecc = {{.bs = 67, .dw = 41, .ns = 3}, {.bs = 135, .dw = 107, .ns = 3}, {.bs = 43, .dw = 15, .ns = 15}, {.bs = 54, .dw = 24, .ns = 15}}}, 105 | {/* Version 21 */ 106 | .data_bytes = 1156, 107 | .apat = {6, 28, 50, 72, 92, 0}, 108 | .ecc = {{.bs = 68, .dw = 42, .ns = 17}, {.bs = 144, .dw = 116, .ns = 4}, {.bs = 46, .dw = 16, .ns = 19}, {.bs = 50, .dw = 22, .ns = 17}}}, 109 | {/* Version 22 */ 110 | .data_bytes = 1258, 111 | .apat = {6, 26, 50, 74, 98, 0}, 112 | .ecc = {{.bs = 74, .dw = 46, .ns = 17}, {.bs = 139, .dw = 111, .ns = 2}, {.bs = 37, .dw = 13, .ns = 34}, {.bs = 54, .dw = 24, .ns = 7}}}, 113 | {/* Version 23 */ 114 | .data_bytes = 1364, 115 | .apat = {6, 30, 54, 78, 102, 0}, 116 | .ecc = {{.bs = 75, .dw = 47, .ns = 4}, {.bs = 151, .dw = 121, .ns = 4}, {.bs = 45, .dw = 15, .ns = 16}, {.bs = 54, .dw = 24, .ns = 11}}}, 117 | {/* Version 24 */ 118 | .data_bytes = 1474, 119 | .apat = {6, 28, 54, 80, 106, 0}, 120 | .ecc = {{.bs = 73, .dw = 45, .ns = 6}, {.bs = 147, .dw = 117, .ns = 6}, {.bs = 46, .dw = 16, .ns = 30}, {.bs = 54, .dw = 24, .ns = 11}}}, 121 | {/* Version 25 */ 122 | .data_bytes = 1588, 123 | .apat = {6, 32, 58, 84, 110, 0}, 124 | .ecc = {{.bs = 75, .dw = 47, .ns = 8}, {.bs = 132, .dw = 106, .ns = 8}, {.bs = 45, .dw = 15, .ns = 22}, {.bs = 54, .dw = 24, .ns = 7}}}, 125 | {/* Version 26 */ 126 | .data_bytes = 1706, 127 | .apat = {6, 30, 58, 86, 114, 0}, 128 | .ecc = {{.bs = 74, .dw = 46, .ns = 19}, {.bs = 142, .dw = 114, .ns = 10}, {.bs = 46, .dw = 16, .ns = 33}, {.bs = 50, .dw = 22, .ns = 28}}}, 129 | {/* Version 27 */ 130 | .data_bytes = 1828, 131 | .apat = {6, 34, 62, 90, 118, 0}, 132 | .ecc = {{.bs = 73, .dw = 45, .ns = 22}, {.bs = 152, .dw = 122, .ns = 8}, {.bs = 45, .dw = 15, .ns = 12}, {.bs = 53, .dw = 23, .ns = 8}}}, 133 | {/* Version 28 */ 134 | .data_bytes = 1921, 135 | .apat = {6, 26, 50, 74, 98, 122, 0}, 136 | .ecc = {{.bs = 73, .dw = 45, .ns = 3}, {.bs = 147, .dw = 117, .ns = 3}, {.bs = 45, .dw = 15, .ns = 11}, {.bs = 54, .dw = 24, .ns = 4}}}, 137 | {/* Version 29 */ 138 | .data_bytes = 2051, 139 | .apat = {6, 30, 54, 78, 102, 126, 0}, 140 | .ecc = {{.bs = 73, .dw = 45, .ns = 21}, {.bs = 146, .dw = 116, .ns = 7}, {.bs = 45, .dw = 15, .ns = 19}, {.bs = 53, .dw = 23, .ns = 1}}}, 141 | {/* Version 30 */ 142 | .data_bytes = 2185, 143 | .apat = {6, 26, 52, 78, 104, 130, 0}, 144 | .ecc = {{.bs = 75, .dw = 47, .ns = 19}, {.bs = 145, .dw = 115, .ns = 5}, {.bs = 45, .dw = 15, .ns = 23}, {.bs = 54, .dw = 24, .ns = 15}}}, 145 | {/* Version 31 */ 146 | .data_bytes = 2323, 147 | .apat = {6, 30, 56, 82, 108, 134, 0}, 148 | .ecc = {{.bs = 74, .dw = 46, .ns = 2}, {.bs = 145, .dw = 115, .ns = 13}, {.bs = 45, .dw = 15, .ns = 23}, {.bs = 54, .dw = 24, .ns = 42}}}, 149 | {/* Version 32 */ 150 | .data_bytes = 2465, 151 | .apat = {6, 34, 60, 86, 112, 138, 0}, 152 | .ecc = {{.bs = 74, .dw = 46, .ns = 10}, {.bs = 145, .dw = 115, .ns = 17}, {.bs = 45, .dw = 15, .ns = 19}, {.bs = 54, .dw = 24, .ns = 10}}}, 153 | {/* Version 33 */ 154 | .data_bytes = 2611, 155 | .apat = {6, 30, 58, 86, 114, 142, 0}, 156 | .ecc = {{.bs = 74, .dw = 46, .ns = 14}, {.bs = 145, .dw = 115, .ns = 17}, {.bs = 45, .dw = 15, .ns = 11}, {.bs = 54, .dw = 24, .ns = 29}}}, 157 | {/* Version 34 */ 158 | .data_bytes = 2761, 159 | .apat = {6, 34, 62, 90, 118, 146, 0}, 160 | .ecc = {{.bs = 74, .dw = 46, .ns = 14}, {.bs = 145, .dw = 115, .ns = 13}, {.bs = 46, .dw = 16, .ns = 59}, {.bs = 54, .dw = 24, .ns = 44}}}, 161 | {/* Version 35 */ 162 | .data_bytes = 2876, 163 | .apat = {6, 30, 54, 78, 102, 126, 150}, 164 | .ecc = {{.bs = 75, .dw = 47, .ns = 12}, {.bs = 151, .dw = 121, .ns = 12}, {.bs = 45, .dw = 15, .ns = 22}, {.bs = 54, .dw = 24, .ns = 39}}}, 165 | {/* Version 36 */ 166 | .data_bytes = 3034, 167 | .apat = {6, 24, 50, 76, 102, 128, 154}, 168 | .ecc = {{.bs = 75, .dw = 47, .ns = 6}, {.bs = 151, .dw = 121, .ns = 6}, {.bs = 45, .dw = 15, .ns = 2}, {.bs = 54, .dw = 24, .ns = 46}}}, 169 | {/* Version 37 */ 170 | .data_bytes = 3196, 171 | .apat = {6, 28, 54, 80, 106, 132, 158}, 172 | .ecc = {{.bs = 74, .dw = 46, .ns = 29}, {.bs = 152, .dw = 122, .ns = 17}, {.bs = 45, .dw = 15, .ns = 24}, {.bs = 54, .dw = 24, .ns = 49}}}, 173 | {/* Version 38 */ 174 | .data_bytes = 3362, 175 | .apat = {6, 32, 58, 84, 110, 136, 162}, 176 | .ecc = {{.bs = 74, .dw = 46, .ns = 13}, {.bs = 152, .dw = 122, .ns = 4}, {.bs = 45, .dw = 15, .ns = 42}, {.bs = 54, .dw = 24, .ns = 48}}}, 177 | {/* Version 39 */ 178 | .data_bytes = 3532, 179 | .apat = {6, 26, 54, 82, 110, 138, 166}, 180 | .ecc = {{.bs = 75, .dw = 47, .ns = 40}, {.bs = 147, .dw = 117, .ns = 20}, {.bs = 45, .dw = 15, .ns = 10}, {.bs = 54, .dw = 24, .ns = 43}}}, 181 | {/* Version 40 */ 182 | .data_bytes = 3706, 183 | .apat = {6, 30, 58, 86, 114, 142, 170}, 184 | .ecc = {{.bs = 75, .dw = 47, .ns = 18}, {.bs = 148, .dw = 118, .ns = 19}, {.bs = 45, .dw = 15, .ns = 20}, {.bs = 54, .dw = 24, .ns = 34}}}}; 185 | --------------------------------------------------------------------------------