Files
spectra/docs/display-orientation.md

3.8 KiB
Raw Blame History

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:

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.