1 #include "qr.h"
2 
3 #include "debug.h"
4 #include "stb.h"
5 #include "tox.h"
6 #include "self.h"
7 
8 #include "native/image.h"
9 
10 #include <qrcodegen.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #define QR_BORDER_SIZE 4 /* unit: QR modules */
16 
generate_qr(const char * text,uint8_t * qrcode)17 static bool generate_qr(const char *text, uint8_t *qrcode)
18 {
19     uint8_t temp_buffer[qrcodegen_BUFFER_LEN_MAX];
20     return qrcodegen_encodeText(text, temp_buffer, qrcode, qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN,
21         qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
22 }
23 
convert_qr_to_rgb(const uint8_t * qrcode,uint8_t size,uint8_t * pixels)24 static void convert_qr_to_rgb(const uint8_t *qrcode, uint8_t size, uint8_t *pixels)
25 {
26     /* skip first border on y and x axis */
27     uint16_t i = ((QR_BORDER_SIZE * size) + QR_BORDER_SIZE) * 3;
28     for (uint8_t y = 0; y < qrcodegen_getSize(qrcode); y++) {
29         for (uint8_t x = 0; x < qrcodegen_getSize(qrcode); x++) {
30             bool black = qrcodegen_getModule(qrcode, x, y);
31             pixels[i] = pixels[i + 1] = pixels[i + 2] = black ? 0x00 : 0xFF;
32             i += 3;
33         }
34         /* skip border until end of line and border on start of next line */
35         i += (QR_BORDER_SIZE * 2) * 3;
36     }
37 }
38 
qr_setup(const char * id_str,uint8_t ** qr_data,int * qr_data_size,NATIVE_IMAGE ** qr_image,int * qr_image_size)39 void qr_setup(const char *id_str, uint8_t **qr_data, int *qr_data_size, NATIVE_IMAGE **qr_image, int *qr_image_size)
40 {
41     const uint8_t channel_number = 3;
42     uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX] = { 0 };
43     char tox_uri[TOX_ADDRESS_STR_SIZE + sizeof("tox:")];
44 
45     snprintf(tox_uri, sizeof(tox_uri), "tox:%.*s", (unsigned int) TOX_ADDRESS_STR_SIZE, id_str);
46 
47     if (!generate_qr(tox_uri, qrcode)) {
48         LOG_ERR("QR", "Unable to generate QR code from Tox URI.");
49         return;
50     }
51 
52     *qr_image_size = qrcodegen_getSize(qrcode);
53     *qr_image_size += QR_BORDER_SIZE * 2; /* add border on both sides */
54     uint8_t pixels[*qr_image_size * *qr_image_size * channel_number];
55     memset(pixels, 0xFF, sizeof(pixels)); /* make it all white */
56     convert_qr_to_rgb(qrcode, *qr_image_size, pixels);
57 
58     *qr_data = stbi_write_png_to_mem(pixels, 0, *qr_image_size, *qr_image_size, channel_number, qr_data_size);
59 
60     uint16_t native_size = *qr_image_size;
61     *qr_image = utox_image_to_native(*qr_data, *qr_data_size, &native_size, &native_size, false);
62 }
63