轉自HaaS技術社群
在輕量級RTOS GUI圖形庫中,LittlevGL是一個使用C語言開發,開源免費的GUI,支援觸摸屏,滑鼠,鍵盤多種操作,移植簡單友善,在豐富的控件基礎上還可以自定義控件,開發者一直在不斷完善更新,相對于其他GUI,LittlevGL在硬體資源不足(RAM < 100kbytes)的情況下存在較大的優勢,在240*240的顯示屏上顯示一張圖檔,RAM緩沖區設定為2Kbytes即可。
AliOS Things 目前最新版本已經內建LittlevGL,并且在智能穿戴裝置項目上已商用。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iYkVmYilTM4IjZ0YjZ4YWO5QDZ0IDMllTOhBTO0ITY08CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)
LittlevGL對于圖檔跟字型的使用是預先要使用外部工具,對圖檔跟字型轉成二進制檔案,然後直接使用,在一些簡單固定顯示的應用場景是可以滿足的,而且對記憶體消耗會比較少。但是在一些複雜的應用場景就無法滿足了,比如相機應用中拍照生成的圖檔格式大多為JPEG的,相冊中顯示圖檔就無法提前進行轉換,或者遇到服務端下發JEPG圖檔情況,是以需要對LittlevGL進行擴充。
開源libJPEG庫是用于編碼資料為JPEG格式或者解碼JPEG格式圖檔的常用庫,而libJPEG-turbo則效率更高。考慮到未來除了需要解碼JPEG可能還會遇到需要壓縮JPEG圖檔的場景,是以最終使用libJPEG-turbo來豐富LittlevGL對圖檔支援。
JPEG圖像的解壓縮操作過程
1.為JPEG對象配置設定空間并初始化
2.指定解壓縮資料源
3.擷取檔案資訊
4.為解壓縮設定參數,包括圖像大小,顔色空間
5.開始解壓縮
6.取出資料
7.解壓縮完畢
8.釋放資源
為JPEG對象配置設定空間并初始化
解壓縮過程中使用的JPEG對象是一個jpeg_decompress_struct的結構體。同時還需要定義一個用于錯誤處理的結構體對象,标準的錯誤結構體是jpeg_error_mgr。
#if !USE_LV_DRAW_IMG_JPEG_DECODER_HW_MODE
static struct jpeg_decompress_struct jpeg_info;
static struct jpeg_error_mgr jpeg_error_mgr;
#endif
初始化jpeg_info結構,并将錯誤處理結構對象綁定在JPEG對象上,這個标準的錯誤處理結構将使程式在出現error時調用exit退出程式,如果不希望使用标準的錯誤處理方式,則可以通過自定義退出函數的方法自定義錯誤處理結構。
jpeg_create_decompress(&jpeg_info);
jpeg_info.err = jpeg_std_error(&jpeg_error_mgr);
jpeg_error_mgr.error_exit = jpeg_error_exit;
對jpeg_info配置設定記憶體并将圖檔的預設資訊填充到jpeg_info。
jpeg_mem_src(&jpeg_info, data_buf, img_dsc->data_size);
if(jpeg_read_header(&jpeg_info, TRUE) == -1) {
LOGE("lv_img_decoder_open_jpeg: read header err !!\n");
if(from_file == 1) {
jpeg_free(data_buf);
data_buf = NULL;
}
return LV_IMG_DECODER_OPEN_FAIL;
}
此時,常見的可用資訊包括圖像的寬jpeg_info.image_width,高jpeg_info.image_height,色彩空間jpeg_info.jpeg_color_space,顔色通道數jpeg_info.num_components等。在完成jpeg_read_header調用後,開始解壓縮之前就可以進行解壓縮參數的設定,也就是為jpeg_info結構的成員指派。
可以設定解出來的圖像與原圖的比例,也可以設定輸出圖像的色彩空間,即cinfo.out_color_space。原圖比例是使用scale_num和scale_denom兩個參數,解出來的圖像大小就是scale_num/scale_denom,目前僅支援1/1, 1/2, 1/4,和1/8這幾種縮小比例,如果沒有額外要求,以上參數使用預設即可。
比如要取得1/2原圖的圖像,把一個原本彩色的圖像由真彩色JCS_RGB變為灰階JCS_GRAYSCALE。需要如下設定:
jpeg_info.scale_num=1;
jpeg_info.scale_denom=2;
jpeg_info.out_color_space=JCS_GRAYSCALE;
根據設定的解壓縮參數進行圖像解壓縮操作。
if((jpeg_start_decompress(&jpeg_info) == false) || (jpeg_err == 1)) {
LOGE("lv_img_decoder_open_jpeg: decompress failed !!\n");
if(from_file == 1) {
jpeg_free(data_buf);
data_buf = NULL;
}
return LV_IMG_DECODER_OPEN_FAIL;
}
在完成解壓縮操作後,要開始為取走資料做準備,将解壓後的圖像資訊填充至jpeg_info結構中。比如,輸出圖像寬度jpeg_info.output_width,輸出圖像高度jpeg_info.output_height,每個像素中的顔色通道數jpeg_info.output_components(比如灰階為1,全彩色為3)等。一般情況下,這些參數是在jpeg_start_decompress執行後才被填充到jpeg_info中的,如果希望在調用jpeg_start_decompress之前就獲得這些參數,可以通過調用jpeg_calc_output_dimensions()的方法來實作。
uint8_t *rgb888_buf = NULL;
uint32_t out_buffer_size = jpeg_info.image_width*jpeg_info.image_height*jpeg_info.num_components;
rgb888_buf = jpeg_malloc(out_buffer_size, 0);
if(rgb888_buf == NULL) {
LOGI("lv_img_decoder_open_jpeg: no enough memory!!\n");
goto err;
}
解壓縮的資料是按照行取出的,資料像素按照scanline來存儲,scanline是從左到右,從上到下的順序,每個像素對應的各顔色或灰階通道資料是依次存儲,比如一個24-bitRGB真彩色的圖像中,一個scanline中的資料存儲模式是R,G,B,R,G,B,R,G,B,...,每條scanline是一個JSAMPLE類型的數組,一般來說就是unsigned char,定義于jmorecfg.h中。除了JSAMPLE,IJG還定義了JSAMPROW和JSAMPARRAY,分别表示一行JSAMPLE和一個2D的JSAMPLE數組。
jpeg_info.output_scanline表示目前已經讀取的行數,如此即可依次讀出圖像的所有資料,并填充到緩沖區中。
while (jpeg_info.output_scanline<jpeg_info.output_height)
{
JSAMPROW out_str = (JSAMPROW)(rgb888_buf +
jpeg_info.output_scanline*jpeg_info.image_width*jpeg_info.num_components);
if((jpeg_read_scanlines(&jpeg_info, &out_str, 1) != 1) || (jpeg_err == 1)) {
LOGE("lv_img_decoder_open_jpeg: scan line failed!!\n");
jpeg_free((void *)rgb888_buf);
goto err;
}
}
解壓縮完畢調用jpeg_finish_decompress,然後釋放jpeg_destroy_decompress
jpeg_finish_decompress(&jpeg_info);
jpeg_destroy_decompress(&jpeg_info);
開發者支援
如需更多技術支援,可加入釘釘開發者群,或者關注微信公衆号。
更多技術與解決方案介紹,請通路HaaS官方網站
https://haas.iot.aliyun.com。