Files
espresso_frame/firmware/main/manage_qr_overlay.h
T
tfaour e870898490
Build and push server image / build-and-push (push) Successful in 32s
Refine manage overlay: US/CAN state abbreviations, share-QR caption, and an escalating second menu with named-face labels
Two rounds of follow-up work on the manage-button overlay:

1. Location formatting: US/Canada now show abbreviated state/province
   ("CA", "ON") instead of the full name, other countries show the full
   country name, and each is its own line (was one line, now wraps to
   two) so longer international place names have more room without
   threatening to overlap the top-right QR box. The bottom-left share QR
   also gets a "SCAN TO DOWNLOAD" caption.

2. Escalating menu: pressing the manage button again while its overlay
   is already up adds a second level -- each Immich-identified person's
   name labeled next to their face in the photo (using Immich's own
   face recognition/People data, no detection/recognition added to this
   project). A third press exits immediately instead of waiting out the
   30s auto-revert timer. No new Immich API needed -- GET /api/faces
   already embeds a nullable person.name per face; new
   server/app/face_labels.py maps a named face's box into the final
   800x480 frame's pixel space (reusing crop-box math extracted from
   image_pipeline.py's face-aware cropping). Capped at 4 named faces,
   sized to a real firmware RAM budget: each label is its own malloc'd
   overlay region on the device, alongside the 4 fixed corner regions
   already in use. New GET /frame/face-labels returns a flattened
   fixed-slot JSON shape (not a real array) so firmware's existing
   flat-scalar parser can read it without needing an actual array
   parser. No persistent state needed for the escalation itself -- it's
   all local control flow within one continuous awake session
   (frame_client.c's run_management_menu()).
2026-07-19 09:09:06 -04:00

61 lines
2.9 KiB
C

#pragma once
#include <stdint.h>
#include "esp_err.h"
/* 4 fixed corner regions (manage QR, location, date, share QR) plus up
* to MANAGE_FACE_LABELS_MAX arbitrary-position named-face labels (see
* manage_face_label_t below). MANAGE_FACE_LABELS_MAX is capped small
* deliberately, not arbitrarily -- each label is its own malloc'd
* buffer, and the 4 fixed regions alone already use a meaningful chunk
* of the ESP32-C6's limited RAM; this keeps worst-case overlay memory
* well clear of what the WiFi/HTTP stack needs alongside it. */
#define MANAGE_FACE_LABELS_MAX 4
#define MANAGE_OVERLAY_MAX_REGIONS (4 + MANAGE_FACE_LABELS_MAX)
typedef struct {
uint8_t *buf; /* malloc'd (w/2)*h bytes, packed 2px/byte; owned by the region */
int x0, y0; /* top-left corner, panel pixel coordinates (x0 is always even) */
int w, h; /* pixel dimensions (w is always even) */
} manage_overlay_region_t;
typedef struct {
manage_overlay_region_t regions[MANAGE_OVERLAY_MAX_REGIONS];
int count;
} manage_overlay_set_t;
typedef struct {
char name[16];
int x, y; /* anchor point (bottom-center of the face), panel pixel coordinates */
} manage_face_label_t;
typedef struct {
const char *management_url; /* top-right QR + "SCAN TO"/"MANAGE" caption -- always shown */
const char *location_line1; /* top-left text, line 1 (city); NULL/empty skips this region */
const char *location_line2; /* top-left text, line 2 (state/country); NULL/empty is fine if line1 is set */
const char *taken_at; /* bottom-right text; NULL/empty skips this region */
const char *share_url; /* bottom-left QR + "SCAN TO"/"DOWNLOAD" caption; NULL/empty skips this region */
const manage_face_label_t *face_labels; /* named-face labels ("level 2" menu); NULL/empty count skips these */
int face_label_count; /* clamped to MANAGE_FACE_LABELS_MAX internally */
} manage_overlay_content_t;
/**
* Renders the manage-button overlay: always a "scan to manage" QR in the
* top-right corner, plus whichever of location_line1/taken_at/share_url
* are non-NULL/non-empty in their own corners (top-left, bottom-right,
* bottom-left respectively), plus one region per entry in face_labels
* (positioned near that face rather than a fixed corner -- see
* render_face_label_region() in the .c file for the clamping logic).
* Each region is its own separately malloc'd small buffer (not a full
* EPD_FRAME_BYTES frame). A failure rendering the top-right region fails
* the whole call; a failure rendering any other region just skips that
* region and keeps going. Caller must call manage_overlay_free() on out
* regardless of the return value (out->count reflects however many
* regions were actually populated).
*/
esp_err_t manage_overlay_render(const manage_overlay_content_t *content, manage_overlay_set_t *out);
/** Frees every populated region's buffer in overlay. */
void manage_overlay_free(manage_overlay_set_t *overlay);