Screenshot app & service (#42)

- Added screenshot app & service (PC-only for now)
- Updated docs with screenshots and new device photo
- Add fake statusbar icons for PC/sim build
- added `lv_screenshot` library based on `lv_100ask_screenshot` from https://github.com/100askTeam/lv_lib_100ask
- T-Deck WiFi is now allocated into SPI RAM
- Created `tt_service_find()` to find services by their id
This commit is contained in:
Ken Van Hoeylandt
2024-02-11 22:40:53 +01:00
committed by GitHub
parent 0bdc4bd32f
commit 3250943345
34 changed files with 934 additions and 2 deletions
+30
View File
@@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
file(GLOB SOURCES "src/*.c")
file(GLOB HEADERS "src/*.h")
add_library(lv_screenshot STATIC)
target_sources(lv_screenshot
PRIVATE ${SOURCES}
PUBLIC ${HEADERS}
)
target_include_directories(lv_screenshot
PRIVATE private
PUBLIC src
)
if (DEFINED ENV{ESP_IDF_VERSION})
target_link_libraries(lv_screenshot
PUBLIC idf::lvgl
)
else()
target_link_libraries(lv_screenshot
PUBLIC lvgl
)
endif()
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 深圳百问网科技有限公司(www.100ask.net)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+12
View File
@@ -0,0 +1,12 @@
## lv_screenshot
This library is adapted from the lv_100ask_screenshot library from 100ask on [GitHub](https://github.com/100askTeam/lv_lib_100ask).
The original license is available [here](LICENSE-original).
## Features
- Save LVGL screen objects (full screen) as image files: lv_scr_act(),layer_sys(),layer_top()
- Capture and save the specified LVGL object and its children as an image file
- Supported save as: BMP, PNG, JPG
- more todo...
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "lvgl.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool lve_screenshot_save_bmp_file(const uint8_t* image, uint32_t w, uint32_t h, uint32_t bpp, const char* filename);
#ifdef __cplusplus
}
#endif
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "lvgl.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool lv_screenshot_save_png_file(const uint8_t* image, uint32_t w, uint32_t h, uint32_t bpp, const char* filename);
#ifdef __cplusplus
}
#endif
+67
View File
@@ -0,0 +1,67 @@
#include "lv_screenshot.h"
#include "save_bmp.h"
#include "save_png.h"
static void data_pre_processing(lv_img_dsc_t* snapshot, uint16_t bpp, lv_100ask_screenshot_sv_t screenshot_sv);
bool lv_screenshot_create(lv_obj_t* obj, lv_img_cf_t cf, lv_100ask_screenshot_sv_t screenshot_sv, const char* filename) {
lv_img_dsc_t* snapshot = lv_snapshot_take(obj, cf);
if (snapshot) {
data_pre_processing(snapshot, LV_COLOR_DEPTH, screenshot_sv);
if (screenshot_sv == LV_100ASK_SCREENSHOT_SV_PNG) {
if (LV_COLOR_DEPTH == 16) {
lv_screenshot_save_png_file(snapshot->data, snapshot->header.w, snapshot->header.h, 24, filename);
} else if (LV_COLOR_DEPTH == 32) {
lv_screenshot_save_png_file(snapshot->data, snapshot->header.w, snapshot->header.h, 32, filename);
}
} else if (screenshot_sv == LV_100ASK_SCREENSHOT_SV_BMP) {
if (LV_COLOR_DEPTH == 16) {
lve_screenshot_save_bmp_file(snapshot->data, snapshot->header.w, snapshot->header.h, 24, filename);
} else if (LV_COLOR_DEPTH == 32) {
lve_screenshot_save_bmp_file(snapshot->data, snapshot->header.w, snapshot->header.h, 32, filename);
}
}
lv_snapshot_free(snapshot);
return true;
}
return false;
}
static void data_pre_processing(lv_img_dsc_t* snapshot, uint16_t bpp, lv_100ask_screenshot_sv_t screenshot_sv) {
if (bpp == 16) {
uint16_t rgb565_data = 0;
uint32_t count = 0;
for (int w = 0; w < snapshot->header.w; w++) {
for (int h = 0; h < snapshot->header.h; h++) {
rgb565_data = (uint16_t)((*(uint8_t*)(snapshot->data + count + 1) << 8) | *(uint8_t*)(snapshot->data + count));
if (screenshot_sv == LV_100ASK_SCREENSHOT_SV_PNG) {
*(uint8_t*)(snapshot->data + count) = (uint8_t)(((rgb565_data) >> 11) << 3);
*(uint8_t*)(snapshot->data + count + 1) = (uint8_t)(((rgb565_data) >> 5) << 2);
*(uint8_t*)(snapshot->data + count + 2) = (uint8_t)(((rgb565_data) >> 0) << 3);
} else if (screenshot_sv == LV_100ASK_SCREENSHOT_SV_BMP) {
*(uint8_t*)(snapshot->data + count) = (uint8_t)(((rgb565_data) >> 0) << 3);
*(uint8_t*)(snapshot->data + count + 1) = (uint8_t)(((rgb565_data) >> 5) << 2);
*(uint8_t*)(snapshot->data + count + 2) = (uint8_t)(((rgb565_data) >> 11) << 3);
}
count += 3;
}
}
} else if ((screenshot_sv == LV_100ASK_SCREENSHOT_SV_PNG) && (bpp == 32)) {
uint8_t tmp_data = 0;
uint32_t count = 0;
for (int w = 0; w < snapshot->header.w; w++) {
for (int h = 0; h < snapshot->header.h; h++) {
tmp_data = *(snapshot->data + count);
*(uint8_t*)(snapshot->data + count) = *(snapshot->data + count + 2);
*(uint8_t*)(snapshot->data + count + 2) = tmp_data;
count += 4;
}
}
}
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "lvgl.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
LV_100ASK_SCREENSHOT_SV_BMP = 0,
LV_100ASK_SCREENSHOT_SV_PNG = 1,
LV_100ASK_SCREENSHOT_SV_LAST
} lv_100ask_screenshot_sv_t;
bool lv_screenshot_create(lv_obj_t* obj, lv_img_cf_t cf, lv_100ask_screenshot_sv_t screenshot_sv, const char* filename);
#ifdef __cplusplus
} /*extern "C"*/
#endif
+93
View File
@@ -0,0 +1,93 @@
#include "save_bmp.h"
typedef struct tagBITMAPFILEHEADER {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} __attribute__((packed)) BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
uint32_t biSize;
uint32_t biwidth;
uint32_t biheight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
uint32_t biXPelsPerMeter;
uint32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} __attribute__((packed)) BITMAPINFOHEADER, *PBITMAPINFOHEADER;
typedef struct tagRGBQUAD {
uint8_t rgbBlue;
uint8_t rgbGreen;
uint8_t rgbRed;
uint8_t rgbReserved;
} __attribute__((packed)) RGBQUAD;
bool lve_screenshot_save_bmp_file(const uint8_t* image, uint32_t w, uint32_t h, uint32_t bpp, const char* filename) {
BITMAPFILEHEADER tBmpFileHead;
BITMAPINFOHEADER tBmpInfoHead;
uint32_t dwSize;
uint32_t bw;
lv_fs_file_t f;
memset(&tBmpFileHead, 0, sizeof(BITMAPFILEHEADER));
memset(&tBmpInfoHead, 0, sizeof(BITMAPINFOHEADER));
lv_fs_res_t res = lv_fs_open(&f, filename, LV_FS_MODE_WR);
if (res != LV_FS_RES_OK) {
LV_LOG_USER("Can't create output file %s", filename);
return false;
}
tBmpFileHead.bfType = 0x4d42;
tBmpFileHead.bfSize = 0x36 + w * h * (bpp / 8);
tBmpFileHead.bfOffBits = 0x00000036;
tBmpInfoHead.biSize = 0x00000028;
tBmpInfoHead.biwidth = w;
tBmpInfoHead.biheight = h;
tBmpInfoHead.biPlanes = 0x0001;
tBmpInfoHead.biBitCount = bpp;
tBmpInfoHead.biCompression = 0;
tBmpInfoHead.biSizeImage = w * h * (bpp / 8);
tBmpInfoHead.biXPelsPerMeter = 0;
tBmpInfoHead.biYPelsPerMeter = 0;
tBmpInfoHead.biClrUsed = 0;
tBmpInfoHead.biClrImportant = 0;
res = lv_fs_write(&f, &tBmpFileHead, sizeof(tBmpFileHead), &bw);
if (bw != sizeof(tBmpFileHead)) {
LV_LOG_USER("Can't write BMP File Head to %s", filename);
return false;
}
res = lv_fs_write(&f, &tBmpInfoHead, sizeof(tBmpInfoHead), &bw);
if (bw != sizeof(tBmpInfoHead)) {
LV_LOG_USER("Can't write BMP File Info Head to %s", filename);
return false;
}
dwSize = w * bpp / 8;
const uint8_t* pPos = image + (h - 1) * dwSize;
while (pPos >= image) {
res = lv_fs_write(&f, pPos, dwSize, &bw);
if (bw != dwSize) {
LV_LOG_USER("Can't write date to BMP File %s", filename);
return false;
}
pPos -= dwSize;
}
lv_fs_close(&f);
return true;
}
+11
View File
@@ -0,0 +1,11 @@
#include "save_png.h"
#include "src/extra/libs/png/lodepng.h"
bool lv_screenshot_save_png_file(const uint8_t* image, uint32_t w, uint32_t h, uint32_t bpp, const char* filename) {
if (bpp == 32) {
return lodepng_encode32_file(filename, image, w, h);
} else if (bpp == 24) {
return lodepng_encode24_file(filename, image, w, h);
}
return false;
}