From eb364cb34ff07bde9e73529470f1346536d7312f Mon Sep 17 00:00:00 2001 From: Adolfo Date: Wed, 29 Jul 2026 22:00:18 -0400 Subject: [PATCH] Scale Immich photos to cover the display --- Apps/ImmichElias/main/Source/main.c | 43 +++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/Apps/ImmichElias/main/Source/main.c b/Apps/ImmichElias/main/Source/main.c index 76a23e0..7843a00 100644 --- a/Apps/ImmichElias/main/Source/main.c +++ b/Apps/ImmichElias/main/Source/main.c @@ -483,6 +483,38 @@ static void fetch_task_fn(void* arg); static void hide_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) { if (!ctx) return; 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); lv_image_set_src(ctx->img_page, lvgl_path); 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_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 { ESP_LOGW(TAG, "Image file not found for display: %s", ctx->saved_img_path); lv_image_set_src(ctx->img_page, LV_SYMBOL_IMAGE);