acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_qrcode.c (6368B)

      1 /**
      2  * @file lv_qrcode.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "lv_qrcode.h"
     10 #if LV_USE_QRCODE
     11 
     12 #include "qrcodegen.h"
     13 
     14 /*********************
     15  *      DEFINES
     16  *********************/
     17 #define MY_CLASS &lv_qrcode_class
     18 
     19 /**********************
     20  *      TYPEDEFS
     21  **********************/
     22 
     23 /**********************
     24  *  STATIC PROTOTYPES
     25  **********************/
     26 static void lv_qrcode_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     27 static void lv_qrcode_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     28 
     29 /**********************
     30  *  STATIC VARIABLES
     31  **********************/
     32 
     33 const lv_obj_class_t lv_qrcode_class = {
     34     .constructor_cb = lv_qrcode_constructor,
     35     .destructor_cb = lv_qrcode_destructor,
     36     .base_class = &lv_canvas_class
     37 };
     38 
     39 static lv_coord_t size_param;
     40 static lv_color_t dark_color_param;
     41 static lv_color_t light_color_param;
     42 
     43 /**********************
     44  *      MACROS
     45  **********************/
     46 
     47 /**********************
     48  *   GLOBAL FUNCTIONS
     49  **********************/
     50 
     51 /**
     52  * Create an empty QR code (an `lv_canvas`) object.
     53  * @param parent point to an object where to create the QR code
     54  * @param size width and height of the QR code
     55  * @param dark_color dark color of the QR code
     56  * @param light_color light color of the QR code
     57  * @return pointer to the created QR code object
     58  */
     59 lv_obj_t * lv_qrcode_create(lv_obj_t * parent, lv_coord_t size, lv_color_t dark_color, lv_color_t light_color)
     60 {
     61     LV_LOG_INFO("begin");
     62     size_param = size;
     63     light_color_param = light_color;
     64     dark_color_param = dark_color;
     65 
     66     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
     67     lv_obj_class_init_obj(obj);
     68     return obj;
     69 
     70 }
     71 
     72 /**
     73  * Set the data of a QR code object
     74  * @param qrcode pointer to aQ code object
     75  * @param data data to display
     76  * @param data_len length of data in bytes
     77  * @return LV_RES_OK: if no error; LV_RES_INV: on error
     78  */
     79 lv_res_t lv_qrcode_update(lv_obj_t * qrcode, const void * data, uint32_t data_len)
     80 {
     81     lv_color_t c;
     82     c.full = 1;
     83     lv_canvas_fill_bg(qrcode, c, LV_OPA_COVER);
     84 
     85     if(data_len > qrcodegen_BUFFER_LEN_MAX) return LV_RES_INV;
     86 
     87     lv_img_dsc_t * imgdsc = lv_canvas_get_img(qrcode);
     88 
     89     int32_t qr_version = qrcodegen_getMinFitVersion(qrcodegen_Ecc_MEDIUM, data_len);
     90     if(qr_version <= 0) return LV_RES_INV;
     91     int32_t qr_size = qrcodegen_version2size(qr_version);
     92     if(qr_size <= 0) return LV_RES_INV;
     93     int32_t scale = imgdsc->header.w / qr_size;
     94     if(scale <= 0) return LV_RES_INV;
     95     int32_t remain = imgdsc->header.w % qr_size;
     96 
     97     /* The qr version is incremented by four point */
     98     uint32_t version_extend = remain / (scale << 2);
     99     if(version_extend && qr_version < qrcodegen_VERSION_MAX) {
    100         qr_version = qr_version + version_extend > qrcodegen_VERSION_MAX ?
    101                      qrcodegen_VERSION_MAX : qr_version + version_extend;
    102     }
    103 
    104     uint8_t * qr0 = lv_mem_alloc(qrcodegen_BUFFER_LEN_FOR_VERSION(qr_version));
    105     LV_ASSERT_MALLOC(qr0);
    106     uint8_t * data_tmp = lv_mem_alloc(qrcodegen_BUFFER_LEN_FOR_VERSION(qr_version));
    107     LV_ASSERT_MALLOC(data_tmp);
    108     lv_memcpy(data_tmp, data, data_len);
    109 
    110     bool ok = qrcodegen_encodeBinary(data_tmp, data_len,
    111                                      qr0, qrcodegen_Ecc_MEDIUM,
    112                                      qr_version, qr_version,
    113                                      qrcodegen_Mask_AUTO, true);
    114 
    115     if(!ok) {
    116         lv_mem_free(qr0);
    117         lv_mem_free(data_tmp);
    118         return LV_RES_INV;
    119     }
    120 
    121     lv_coord_t obj_w = imgdsc->header.w;
    122     qr_size = qrcodegen_getSize(qr0);
    123     scale = obj_w / qr_size;
    124     int scaled = qr_size * scale;
    125     int margin = (obj_w - scaled) / 2;
    126     uint8_t * buf_u8 = (uint8_t *)imgdsc->data + 8;    /*+8 skip the palette*/
    127 
    128     /* Copy the qr code canvas:
    129      * A simple `lv_canvas_set_px` would work but it's slow for so many pixels.
    130      * So buffer 1 byte (8 px) from the qr code and set it in the canvas image */
    131     uint32_t row_byte_cnt = (imgdsc->header.w + 7) >> 3;
    132     int y;
    133     for(y = margin; y < scaled + margin; y += scale) {
    134         uint8_t b = 0;
    135         uint8_t p = 0;
    136         bool aligned = false;
    137         int x;
    138         for(x = margin; x < scaled + margin; x++) {
    139             bool a = qrcodegen_getModule(qr0, (x - margin) / scale, (y - margin) / scale);
    140 
    141             if(aligned == false && (x & 0x7) == 0) aligned = true;
    142 
    143             if(aligned == false) {
    144                 c.full = a ? 0 : 1;
    145                 lv_canvas_set_px_color(qrcode, x, y, c);
    146             }
    147             else {
    148                 if(!a) b |= (1 << (7 - p));
    149                 p++;
    150                 if(p == 8) {
    151                     uint32_t px = row_byte_cnt * y + (x >> 3);
    152                     buf_u8[px] = b;
    153                     b = 0;
    154                     p = 0;
    155                 }
    156             }
    157         }
    158 
    159         /*Process the last byte of the row*/
    160         if(p) {
    161             /*Make the rest of the bits white*/
    162             b |= (1 << (8 - p)) - 1;
    163 
    164             uint32_t px = row_byte_cnt * y + (x >> 3);
    165             buf_u8[px] = b;
    166         }
    167 
    168         /*The Qr is probably scaled so simply to the repeated rows*/
    169         int s;
    170         const uint8_t * row_ori = buf_u8 + row_byte_cnt * y;
    171         for(s = 1; s < scale; s++) {
    172             lv_memcpy((uint8_t *)buf_u8 + row_byte_cnt * (y + s), row_ori, row_byte_cnt);
    173         }
    174     }
    175 
    176     lv_mem_free(qr0);
    177     lv_mem_free(data_tmp);
    178     return LV_RES_OK;
    179 }
    180 
    181 
    182 void lv_qrcode_delete(lv_obj_t * qrcode)
    183 {
    184     lv_obj_del(qrcode);
    185 }
    186 
    187 /**********************
    188  *   STATIC FUNCTIONS
    189  **********************/
    190 
    191 static void lv_qrcode_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    192 {
    193     LV_UNUSED(class_p);
    194 
    195     uint32_t buf_size = LV_CANVAS_BUF_SIZE_INDEXED_1BIT(size_param, size_param);
    196     uint8_t * buf = lv_mem_alloc(buf_size);
    197     LV_ASSERT_MALLOC(buf);
    198     if(buf == NULL) return;
    199 
    200     lv_canvas_set_buffer(obj, buf, size_param, size_param, LV_IMG_CF_INDEXED_1BIT);
    201     lv_canvas_set_palette(obj, 0, dark_color_param);
    202     lv_canvas_set_palette(obj, 1, light_color_param);
    203 }
    204 
    205 static void lv_qrcode_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    206 {
    207     LV_UNUSED(class_p);
    208 
    209     lv_img_dsc_t * img = lv_canvas_get_img(obj);
    210     lv_img_cache_invalidate_src(img);
    211     lv_mem_free((void *)img->data);
    212     img->data = NULL;
    213 }
    214 
    215 #endif /*LV_USE_QRCODE*/