First commit with entire first rendition of the project
This commit is contained in:
103
docs/display-orientation.md
Normal file
103
docs/display-orientation.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user