Scale Immich photos to cover the display
This commit is contained in:
@@ -483,6 +483,38 @@ static void fetch_task_fn(void* arg);
|
|||||||
static void hide_chrome(AppCtx* ctx);
|
static void hide_chrome(AppCtx* ctx);
|
||||||
static void show_chrome(AppCtx* ctx);
|
static void show_chrome(AppCtx* ctx);
|
||||||
|
|
||||||
|
static bool get_png_dimensions(const char* path, int* width, int* height) {
|
||||||
|
if (!path || !width || !height) return false;
|
||||||
|
|
||||||
|
uint8_t header[24];
|
||||||
|
FILE* file = fopen(path, "rb");
|
||||||
|
if (!file) return false;
|
||||||
|
size_t read_size = fread(header, 1, sizeof(header), file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
static const uint8_t png_signature[8] = { 0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A };
|
||||||
|
if (read_size != sizeof(header) || memcmp(header, png_signature, sizeof(png_signature)) != 0 ||
|
||||||
|
memcmp(&header[12], "IHDR", 4) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*width = (int)(((uint32_t)header[16] << 24U) | ((uint32_t)header[17] << 16U) |
|
||||||
|
((uint32_t)header[18] << 8U) | (uint32_t)header[19]);
|
||||||
|
*height = (int)(((uint32_t)header[20] << 24U) | ((uint32_t)header[21] << 16U) |
|
||||||
|
((uint32_t)header[22] << 8U) | (uint32_t)header[23]);
|
||||||
|
return *width > 0 && *height > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t get_cover_scale(const AppCtx* ctx, int source_width, int source_height) {
|
||||||
|
if (!ctx || ctx->disp_w <= 0 || ctx->disp_h <= 0 || source_width <= 0 || source_height <= 0) {
|
||||||
|
return 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t scale_x = ((uint32_t)ctx->disp_w * 256U + (uint32_t)source_width - 1U) / (uint32_t)source_width;
|
||||||
|
uint32_t scale_y = ((uint32_t)ctx->disp_h * 256U + (uint32_t)source_height - 1U) / (uint32_t)source_height;
|
||||||
|
return scale_x > scale_y ? scale_x : scale_y;
|
||||||
|
}
|
||||||
|
|
||||||
static void detect_display_size(AppCtx* ctx, lv_obj_t* parent) {
|
static void detect_display_size(AppCtx* ctx, lv_obj_t* parent) {
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
int w=FALLBACK_W, h=FALLBACK_H;
|
int w=FALLBACK_W, h=FALLBACK_H;
|
||||||
@@ -575,10 +607,17 @@ static void ui_update_all(AppCtx* ctx) {
|
|||||||
snprintf(lvgl_path, sizeof(lvgl_path), "A:%s", ctx->saved_img_path);
|
snprintf(lvgl_path, sizeof(lvgl_path), "A:%s", ctx->saved_img_path);
|
||||||
lv_image_set_src(ctx->img_page, lvgl_path);
|
lv_image_set_src(ctx->img_page, lvgl_path);
|
||||||
lv_obj_clear_flag(ctx->img_page, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_clear_flag(ctx->img_page, LV_OBJ_FLAG_HIDDEN);
|
||||||
// Fullscreen background: widget covers entire display
|
// Scale the memory-safe 320x240 source to cover the display while
|
||||||
|
// preserving its aspect ratio. The parent clips the excess.
|
||||||
|
int source_width = ctx->img_w;
|
||||||
|
int source_height = ctx->img_h;
|
||||||
|
get_png_dimensions(ctx->saved_img_path, &source_width, &source_height);
|
||||||
|
uint32_t scale = get_cover_scale(ctx, source_width, source_height);
|
||||||
|
lv_image_set_scale(ctx->img_page, scale);
|
||||||
lv_obj_set_size(ctx->img_page, ctx->disp_w > 0 ? ctx->disp_w : ctx->img_w, ctx->disp_h > 0 ? ctx->disp_h : ctx->img_h);
|
lv_obj_set_size(ctx->img_page, ctx->disp_w > 0 ? ctx->disp_w : ctx->img_w, ctx->disp_h > 0 ? ctx->disp_h : ctx->img_h);
|
||||||
lv_obj_center(ctx->img_page);
|
lv_obj_center(ctx->img_page);
|
||||||
ESP_LOGI(TAG, "lv_img_set_src %s %dx%d", lvgl_path, ctx->disp_w, ctx->disp_h);
|
ESP_LOGI(TAG, "lv_img_set_src %s display %dx%d source %dx%d scale %u",
|
||||||
|
lvgl_path, ctx->disp_w, ctx->disp_h, source_width, source_height, (unsigned)scale);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "Image file not found for display: %s", ctx->saved_img_path);
|
ESP_LOGW(TAG, "Image file not found for display: %s", ctx->saved_img_path);
|
||||||
lv_image_set_src(ctx->img_page, LV_SYMBOL_IMAGE);
|
lv_image_set_src(ctx->img_page, LV_SYMBOL_IMAGE);
|
||||||
|
|||||||
Reference in New Issue
Block a user