資安

LittlevGL圖形框架擴展 – 二維碼的支持

轉自HaaS技術社區

1、二維碼發展史

二維碼這個小圖案現在已經是我們生活中不可或缺的一部分了,飯店點餐,添加好友,付錢轉賬,登錄賬號等等都只要掃一掃,方便又快捷。二維碼的前身其實就是一維碼,也就是條形碼。

條形碼可以在水平方向,通過黑白相間的條紋來存儲一些數字或者字母的信息,製作十分簡單,但是有著存儲容量不足、易複製、無法表示漢字等缺點,為此人們繼續考慮同時從水平方向與垂直方向去存儲信息,進而在上世紀90年代產生了二維碼,並開始廣泛運用於生活。二維碼用某種特定的幾何圖形按一定規律在二維空間上分佈的黑白相間的圖形中記錄數據符號信息。

2、跟條形碼區別

2.1、承載的信息量遠大於條形碼

組成條形碼的信息部分只能是字母和數字,而且尺寸較大,導致空間利用率較低。這就決定了其信息量不大的侷限性。它的數據容量較小一般只可容納30個字符左右。二維碼就不一樣了,它的信息承載量很大,最大數據含量可達1850個字符。信息內容可包含字母,數字,漢字,字符,片假名等。信息含量非常豐富。所以二維碼也逐漸被市場所接受,漢字的加入更開拓了中國這個大市場。

2.2、信息表達方式不一樣

根據其特性及結構可以看到,條形碼只能在水平方向單向的表達商品信息,而在垂直方向則不表達任何信息,它有一定高度通常是為了便於條碼設備的對準讀取。而二維碼在水平和垂直方向都可表達信息,也就是說它在二維空間內存儲信息。

2.3、外在結構不一樣

image.png

image.png

根據上圖可知,它們的結構完全不同。條形碼是用條空在水平方向上表達信息的條碼。外形更接近矩形。二維碼可以說是正方形,在其內部有三個“回”字型的定位點,可以幫助掃碼設備對焦,便於讀取數據。也正是它們結構的差異,使條形碼沒有較強的糾錯功能,如果有破損就不能被讀取。對於二維碼來說,即使有破損,也可以正常讀取。其破損糾錯率可達7%~30%。

2.4、碼制不一樣

在目前的碼制中,條形碼和二維碼各有自己的碼制和組成成員。常用的條形碼的碼制包括:EAN碼、39碼、交叉25碼、UPC碼、128碼、93碼,ISBN碼,及Codabar(庫德巴碼)等;常用的二維碼碼制有:PDF417二維條碼, Datamatrix二維條碼, , QR Code, Code 49, Code 16K ,Code one等。

2.5、優缺點表現

一維碼的優點是在一個方向表達信息,其一定的高度通常是為了便於掃描器的對準、一維碼可以提高信息錄入的速度,減少差錯率。缺點是數據的容量比較小,需要計算機數據庫,一維碼被破壞後便不能讀取,容錯率低。

二維碼的優點是信息容量大,編碼範圍廣,成本較低,容易製作,不需要數據庫本身就能儲存大量數據,二維碼的容錯機制保證了圖片部分被破壞後還能正確識別,容錯率可以高達30%。缺點是容易被不法分子植入病毒盜取用戶信息或各種吸費軟件。

3、LittlevGL對條形碼及二維碼的支持

在POS機等支付行業,二維碼比條形碼更為常用,因此圖形框架對二維碼的支持也是必須的,在二維碼中QR Code對字母,數字,漢字等支持的容量很大,因此GUI圖形框架的擴展主要考慮對QR Code的支持。

目前LittlevGL並不支持QR code碼,因此添加如下代碼,其中int16 width代表生成的二維碼的寬跟高,char *cid則是二維碼對應的字符串:

lv_obj_t *qrcode_gen(lv_obj_t * par, const char *cid, int px, int py, int width)
 
{
 
    int src_buf_size, dst_buf_size, qr_w, idx;
 
    int qr_pixel_width = 1;
 
    int version = QR_STD_VERSION;
 
    unsigned char *qr_data;
 
    QRcode *qrcode;
 
 
 
    if(par == NULL) par = lv_scr_act();
 
    qrcode = QRcode_encodeString(cid, version, QR_ECLEVEL_Q, QR_MODE_8, 1);
 
    if ((!qrcode) || (qrcode->width <= 0)) {
 
        printf("QRcode_encodeString failed\n");
 
        return NULL;
 
    }
 
 
 
    qr_w = qrcode->width;
 
    if(width > qr_w) {
 
        qr_pixel_width = width / qr_w;
 
    }
 
 
 
    src_buf_size = qr_w * qr_w * qr_pixel_width * qr_pixel_width * sizeof(lv_color_t);
 
    dst_buf_size = width * width * 2;
 
 
 
    lv_color_t *orig_color_map = lv_mem_aligned_alloc(src_buf_size, 32);
 
    if(orig_color_map == NULL) {
 
        printf("qrcode_gen, no memory 1!!\n");
 
        goto err;
 
    }
 
    memset(orig_color_map, 0x00, src_buf_size);
 
 
 
    qr_data = qrcode->data;
 
    printf("qr width: %d\n", qrcode->width);
 
    int p1;
 
    for (int y = 0; y < qr_w; y++) {
 
        for (int x = 0; x < qr_w; x++) {
 
            idx = y*qr_w + x;
 
            p1 = y * qr_w * (qr_pixel_width * qr_pixel_width) + x * qr_pixel_width;
 
            if ((qr_data[idx] & 0x1) == 0) { /* white pix */
 
                int i = 0;
 
                int p2 = p1;
 
                for(i = 0; i < qr_pixel_width; i++) {
 
                    memset(&orig_color_map[p2], 0xff, sizeof(lv_color_t) * qr_pixel_width);
 
                    p2 += (qr_w * qr_pixel_width);
 
                }
 
            }
 
        }
 
    }
 
 
 
    lv_color_t *dst_color_map = lv_mem_aligned_alloc(dst_buf_size, 32);
 
    if(dst_color_map == NULL) {
 
        printf("qrcode_gen, no memory 2!!\n");
 
        lv_mem_aligned_free(orig_color_map);
 
        goto err;
 
    }
 
 
 
    if(rgb565_scale(qr_w * qr_pixel_width, qr_w * qr_pixel_width, width, width, (uint8_t *)orig_color_map, (uint8_t *)dst_color_map) == 0) {
 
        lv_mem_aligned_free(orig_color_map);
 
        lv_mem_aligned_free(dst_color_map);
 
        goto err;
 
    }
 
 
 
    lv_img_dsc_t *img_des = lv_mem_alloc(sizeof(lv_img_dsc_t));
 
    if(img_des == NULL) {
 
        printf("qrcode_gen, no memory 3!!\n");
 
        lv_mem_aligned_free(orig_color_map);
 
        lv_mem_aligned_free(dst_color_map);
 
        goto err;
 
    }
 
    memset(img_des, 0 , sizeof(lv_img_dsc_t));
 
    img_des->header.w = width;
 
    img_des->header.h = width;
 
    img_des->header.cf = LV_IMG_CF_TRUE_COLOR;
 
    img_des->data_size = dst_buf_size;
 
    img_des->data = (const uint8_t *)dst_color_map;
 
 
 
    lv_obj_t *img = lv_img_create(par, NULL);
 
    lv_img_set_src(img, img_des);
 
 
 
    lv_obj_set_pos(img, px, py);
 
    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(img);
 
    /*The signal and design functions are not copied so set them here*/
 
    lv_obj_set_signal_func(img, qrcode_signal);
 
 
 
    QRcode_free(qrcode);
 
    lv_mem_aligned_free(orig_color_map);
 
    return img;
 
err:
 
    QRcode_free(qrcode);
 
    printf("qrcode_gen failed\n");
 
    return NULL;
 
}

4、總結

本文講解了二維碼的發展史,已經二維碼和條形碼的區別,並詳細的說明如何在LittlevGL中擴展對條形碼及二維碼的支持。

開發者支持

如需更多技術支持,可加入釘釘開發者群,或者關注微信公眾號。

image.png

更多技術與解決方案介紹,請訪問HaaS官方網站https://haas.iot.aliyun.com

Leave a Reply

Your email address will not be published. Required fields are marked *