最近在用ESP32S3获取B站JPG头像进行显示。记录一下,开发板链接:
ESP32-S3 LVGL 开发板 人工智能语音识别 人脸识别 触摸 音频-淘宝网 (taobao.com)
直接上代码:
第一种下载方式:
/*
获取B站头像JPG文件buffer
*/
static esp_err_t face_http_event_handler(esp_http_client_event_t *evt)
{
static char *output_buffer; // Buffer to store response of http request from event handler
static int output_len; // Stores number of bytes read
switch (evt->event_id)
{
case HTTP_EVENT_ERROR:
ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
printf("HTTP_EVENT_ON_DATA, len=%d\n", evt->data_len);
//如果404或者502
// if (evt->data_len == 150 || evt->data_len == 146)
// return ESP_OK;
// printf("%.*s\n", evt->data_len, (char *)evt->data);
// if (!esp_http_client_is_chunked_response(evt->client)) {
// // Write out data
// printf("%.*s", evt->data_len, (char*)evt->data);
// }
if (!esp_http_client_is_chunked_response(evt->client))
{
//ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA !esp_http_client_is_chunked_response");
// If user_data buffer is configured, copy the response into the buffer
if (face_buffer) /*如果已经申请了内存 就直接复制接收到的数据*/
{
memcpy(face_buffer + output_len, evt->data, evt->data_len);
}
else /*如果没有申请*/
{
if (face_buffer == NULL) /*申请一个http长度的内存来保存数据*/
{
face_buffer = (char *)malloc(esp_http_client_get_content_length(evt->client));
output_len = 0;
if (face_buffer == NULL)
{
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
memcpy(face_buffer + output_len, evt->data, evt->data_len); //拷贝数据
}
output_len += evt->data_len; //记录下载进度
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
break;
}
return ESP_OK;
}
void get_face_jpg(char *bili_uid)
{
static esp_http_client_config_t config = {
.url = "https://whycan.com/files/members/4115/11111.png",//这里是你的B站头像链接
.event_handler = face_http_event_handler,
.buffer_size = 3 * 1024,
.timeout_ms = 4000,
.path = "/get",
.transport_type = HTTP_TRANSPORT_OVER_TCP,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_header(client, "Accept", "*/*");
esp_http_client_set_header(client, "Accept-Encoding", "identity");
esp_http_client_set_header(client, "User-Agent", "PostmanRuntime/7.24.1");
esp_http_client_set_header(client, "Connection", "keep-alive");
esp_http_client_set_header(client, "Content-Type", "application/json");
// esp_err_t err = esp_http_client_open(client, 0);
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK)
{
ESP_LOGE(TAG, "HTTP GET Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
}
else
{
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}
esp_http_client_cleanup(client);
}
以上方式是获取一个固定链接的图片存到face_buffer 这个char*里,下一种是先根据B站id来获取头像图片的url,再根据url来获取图片。
B站个人信息API接口:https://api.bilibili.com/x/space/acc/info?mid=59041601
在浏览器里输入以上链接可以看到:
{"code":0,"message":"0","ttl":1,"data":{"mid":59041601,"name":"Kevincoooool","sex":"男","face":"http://i2.hdslb.com/bfs/face/bce14f5e3af4bca480fc7de227986ba304507078.jpg","face_nft":0,"sign":"Jlink DAP OpenMV 淘宝店铺:酷世DIY","rank":10000,"level":5,"jointime":0,"moral":0,"silence":0,"coins":1249,"fans_badge":true,"fans_medal":{"show":true,"wear":false,"medal":null},"official":{"role":0,"title":"","desc":"","type":-1},"vip":{"type":0,"status":0,"due_date":0,"vip_pay_type":0,"theme_type":0,"label":{"path":"","text":"","label_theme":"","text_color":"","bg_style":0,"bg_color":"","border_color":""},"avatar_subscript":0,"nickname_color":"","role":0,"avatar_subscript_url":""},"pendant":{"pid":0,"name":"","image":"","expire":0,"image_enhance":"","image_enhance_frame":""},"nameplate":{"nid":10,"name":"见习偶像","image":"http://i0.hdslb.com/bfs/face/e93dd9edfa7b9e18bf46fd8d71862327a2350923.png","image_small":"http://i2.hdslb.com/bfs/face/275b468b043ec246737ab8580a2075bee0b1263b.png","level":"普通勋章","condition":"所有自制视频总播放数\u003e=10万"},"user_honour_info":{"mid":0,"colour":null,"tags":[]},"is_followed":false,"top_photo":"http://i0.hdslb.com/bfs/space/cb1c3ef50e22b6096fde67febe863494caefebad.png","theme":{},"sys_notice":{},"live_room":{"roomStatus":1,"liveStatus":0,"url":"https://live.bilibili.com/2153512","title":"啥呀这是","cover":"http://i0.hdslb.com/bfs/live/user_cover/20e11be91ed85436a8800dafb3d3550736cb1899.jpg","online":0,"roomid":2153512,"roundStatus":0,"broadcast_type":0},"birthday":"03-08","school":{"name":"成都信息工程大学"},"profession":{"name":""},"tags":null,"series":{"user_upgrade_status":3,"show_upgrade_window":false}}}
其中?"face":"http://i2.hdslb.com/bfs/face/bce14f5e3af4bca480fc7de227986ba304507078.jpg" 就是我们的头像图片链接,再把这个链接放到以上方式的url中即可。
上代码:
esp_err_t cjson_face(char *text)
{
cJSON *root_ksdiy, *psub_ksdiy;
char *index = strchr(text, '{');
printf("face json:%s\n", text);
if (index == NULL)
{
return ESP_FAIL;
}
else
{
strcpy(text, index);
root_ksdiy = cJSON_Parse(text);
if (root_ksdiy != NULL)
{
psub_ksdiy = cJSON_GetObjectItem(root_ksdiy, "data");
if (psub_ksdiy != NULL)
{
cJSON *name = cJSON_GetObjectItem(psub_ksdiy, "name");
wp_fans.name = name->valuestring;
cJSON *face_url = cJSON_GetObjectItem(psub_ksdiy, "face");
wp_fans.face_url = face_url->valuestring;
ESP_LOGI(TAG, "获取头像URL成功 name:%s face_url:%s\n", wp_fans.name, wp_fans.face_url);
memset((char *)url_buff, 0, 256);
sprintf(url_buff, "%s", face_url->valuestring);
_get_face_url = true;
}
else
{
_get_face_url = false;
ESP_LOGI(TAG, "获取头像URL,请检查uid");
}
}
else
{
return ESP_FAIL;
}
cJSON_Delete(root_ksdiy);
}
return ESP_OK;
}
static esp_err_t bilibili_face_http_event_handler(esp_http_client_event_t *evt)
{
switch (evt->event_id)
{
case HTTP_EVENT_ERROR:
ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
printf("HTTP_EVENT_ON_DATA, len=%d\n", evt->data_len);
//如果404或者502
if (evt->data_len == 150 || evt->data_len == 146)
return ESP_OK;
// printf("%.*s\n", evt->data_len, (char *)evt->data);
cjson_face((char *)evt->data);
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
break;
}
return ESP_OK;
}
void get_face_url(char *bili_uid)
{
static char post_url[256] = {0};
memset((char *)post_url, 0, 256);
static esp_http_client_config_t config = {
// .url = "https://api.bilibili.com/x/relation/stat?vmid=59041601&jsonp=jsonp",
.event_handler = bilibili_face_http_event_handler,
.buffer_size = 3 * 1024,
.timeout_ms = 4000,
.path = "/get",
.transport_type = HTTP_TRANSPORT_OVER_TCP,
};
sprintf(post_url, "https://api.bilibili.com/x/space/acc/info?mid=%s", bili_uid);
config.url = post_url;
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_header(client, "Accept", "*/*");
esp_http_client_set_header(client, "Accept-Encoding", "identity");
esp_http_client_set_header(client, "User-Agent", "PostmanRuntime/7.24.1");
esp_http_client_set_header(client, "Connection", "keep-alive");
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK)
{
ESP_LOGE(TAG, "HTTP GET Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
}
else
{
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}
esp_http_client_cleanup(client);
}
最后,获取了B站的头像buffer,我们还要显示出来,在这里要使用到lvgl的split jpg库并对库做一些修改,因为原来的库是不会缩放jpg的,我们得到的头像buffer一般比较大,显示出来整个屏幕都没了,所以需要缩小,
?
.H文件中增加以下define:
/*********************
* DEFINES
*********************/
/* Scaling factor */
// #define LV_TJPGD_CONFIG_SCALING_FACTOR_NONE
//#define LV_TJPGD_CONFIG_SCALING_FACTOR_1_2
#define LV_TJPGD_CONFIG_SCALING_FACTOR_1_4
//#define LV_TJPGD_CONFIG_SCALING_FACTOR_1_8
/* When setting scaling factor to none we should set JD_USE_SCALE to 0
* set it to 1 otherwise */
#if defined (LV_TJPGD_CONFIG_SCALING_FACTOR_NONE)
#define LV_TJPGD_SCALING_FACTOR 0
#define LV_TJPGD_SCALING_FACTOR_DIV 1
#elif defined (LV_TJPGD_CONFIG_SCALING_FACTOR_1_2)
#define LV_TJPGD_SCALING_FACTOR 1
#define LV_TJPGD_SCALING_FACTOR_DIV 2
#elif defined (LV_TJPGD_CONFIG_SCALING_FACTOR_1_4)
#define LV_TJPGD_SCALING_FACTOR 2
#define LV_TJPGD_SCALING_FACTOR_DIV 4
#elif defined (LV_TJPGD_CONFIG_SCALING_FACTOR_1_8)
#define LV_TJPGD_SCALING_FACTOR 3
#define LV_TJPGD_SCALING_FACTOR_DIV 8
#else
#error "Invalid TJPGD scaling factor configuration"
#endif // defined
?最后显示:
lv_img_dsc_t bili_face = {
.header.always_zero = 0,
.header.w = 300,
.header.h = 300,
.data_size = 300 * 300 * 2,
.header.cf = LV_IMG_CF_RAW,
.data = NULL,
};
img_face = lv_img_create(scr_body, NULL);
lv_obj_add_style(img_face, LV_IMG_PART_MAIN, &style_img);
lv_obj_set_pos(img_face, APP_WIN_WIDTH / 2 - 40, 70);
bili_face.data = (uint8_t *)face_buffer;//把在线获取的buffer给img
lv_img_set_src(img_face, &bili_face);
?
|