104 lines
3.8 KiB
Markdown
104 lines
3.8 KiB
Markdown
# Display Orientation
|
||
|
||
## Purpose
|
||
|
||
Allow the user to configure the physical orientation of the Inky Impression
|
||
display so that images are displayed upright regardless of how the panel is
|
||
mounted. The orientation setting also drives the Unsplash orientation filter so
|
||
fetched photos match the display's effective aspect ratio (portrait vs.
|
||
landscape).
|
||
|
||
## Configuration
|
||
|
||
A new `display.orientation` key (integer, degrees clockwise) in
|
||
`config.yaml` / `DEFAULT_CONFIG`:
|
||
|
||
```yaml
|
||
display:
|
||
orientation: 0 # 0, 90, 180, 270
|
||
```
|
||
|
||
| Value | Unsplash filter | Effective aspect |
|
||
|-------|----------------|------------------|
|
||
| 0 | landscape | width > height |
|
||
| 90 | portrait | height > width |
|
||
| 180 | landscape | width > height |
|
||
| 270 | portrait | height > width |
|
||
|
||
The old `unsplash.orientation` config key is **no longer used** by
|
||
`refresh()` — orientation is now derived from `display.orientation` +
|
||
`display.resolution`.
|
||
|
||
## Image Processing Pipeline
|
||
|
||
1. **Fetch** raw photo from Unsplash (with orientation filter already matching
|
||
the effective aspect ratio — see below).
|
||
2. **`process_image()`** in `InkyDisplay`:
|
||
- Compute effective width/height by swapping physical dimensions when
|
||
orientation is 90° or 270°.
|
||
- Crop to effective aspect ratio.
|
||
- Resize to effective dimensions.
|
||
- Rotate by `-orientation` degrees (so the result matches the physical
|
||
resolution of the display panel).
|
||
3. **`show()`** sends the processed (and rotated) image to `inky.set_image()`.
|
||
No additional transformation is needed — the panel hardware always expects
|
||
its native `width × height` pixel grid.
|
||
|
||
## Unsplash Filter Derivation
|
||
|
||
In `cli.py:refresh()`, after reading `display.orientation` and
|
||
`display.resolution`:
|
||
|
||
1. If orientation is 90 or 270, swap width ↔ height to get effective
|
||
dimensions.
|
||
2. If effective height > effective width → request `"portrait"`.
|
||
3. If effective width > effective height → request `"landscape"`.
|
||
4. If roughly equal → request `"squarish"`.
|
||
|
||
This means the Unsplash API is sent `orientation=portrait` when the display is
|
||
mounted vertically, which returns taller photos that need less cropping.
|
||
|
||
## Hot-Reload
|
||
|
||
`_reload_config()` in `cli.py` detects changes to
|
||
`display.orientation` and updates `display.orientation` live. The next
|
||
`process_image()` call uses the new orientation. No display loop restart is
|
||
needed.
|
||
|
||
## Library Caching
|
||
|
||
`_save_to_library()` passes the **effective** width/height to
|
||
`save_unsplash_image()` (swapped when orientation is 90/270). The stored image
|
||
is processed to the effective dimensions at orientation=0 (no rotation). This
|
||
keeps library images in their "natural" viewing orientation.
|
||
|
||
The preview endpoint (`/api/preview/<id>`) creates an `InkyDisplay` with the
|
||
current orientation, so the preview matches what the physical display shows.
|
||
|
||
## UI
|
||
|
||
Settings page (Display article) shows a `<select>` with four options:
|
||
|
||
- 0° (Landscape)
|
||
- 90° (Portrait)
|
||
- 180° (Landscape)
|
||
- 270° (Portrait)
|
||
|
||
Saved via the existing `PUT /api/config/display/orientation` route.
|
||
|
||
The old `unsplash.orientation` dropdown has been **removed** from the settings
|
||
page — it is now auto-derived from the display orientation.
|
||
|
||
## Edge Cases
|
||
|
||
- **0° (default):** No rotation applied. Preserves existing behavior.
|
||
- **180°:** Image is cropped/resized at physical dimensions, then rotated
|
||
upside-down. No dimension swap. Useful for ceiling-mounted displays.
|
||
- **90° / 270°:** Width and height are swapped for cropping/resizing, then
|
||
rotated back to physical dimensions. Images fetched from Unsplash with the
|
||
matching portrait/landscape filter.
|
||
- **Preview:** Shows the rotated image so the user sees exactly what the
|
||
display will show.
|
||
- **rotate(expand=True):** Only used with 90° multiples so no fractional
|
||
pixels appear.
|