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*/