PhoenixKit.Modules.Storage.FocalPoint (phoenix_kit v2.62.2)

Copy Markdown View Source

Where the subject of a photo is, so a rendition can crop around it.

A focal point is {x, y}, fractions of the photo as it is displayed (after its EXIF orientation), 0.0..1.0 from the left and from the top. It is kept in the file's metadata JSON ("focal": x, y and source), so it needs no column. A fixed rendition whose crop mode is focus (V210) crops a window of its shape centered on it (ImageProcessor.resize_and_crop_focus/6); every such rendition of the photo (a square thumbnail, a 4:3, a 16:9) uses the same point, and a photo with none is cropped at the center.

Where it comes from

  • "manual": set by a person (put/4); wins over everything and is never replaced by detection.
  • "auto": found by detect/1, which asks libvips where the photo draws the eye (smartcrop with attention: edges, colour, skin tone) on a copy shrunk to 512px, which costs a few milliseconds. It needs the optional vix package; without it, or when detection fails, there is no point and the crop stays at the center.

ensure/2 is what the generator calls the first time a photo needs one: the stored point, else a detected one (stored for next time), else nil.

Summary

Functions

Forgets the stored focal point and requests regeneration of its subject crops.

Where the photo at path draws the eye, as {:ok, {x, y}} (fractions of the displayed photo), or :error when detection is unavailable or cannot read it.

Whether detection is available (the optional vix package is loaded).

The focal point to crop file around, from its original at local_path: the stored one, else a detected one (stored, so the next rendition does not detect again), else nil. Never raises: a photo detection cannot read is cropped at the center.

The focal point stored on file and where it came from, or nil: {{x, y}, "auto" | "manual"}.

Records a focal point for file: x and y between 0 and 1, source "auto" or "manual". A detected point never replaces a manual one ({:ok, :kept}). Only the "focal" key of the metadata changes. A change of point also invalidates generated subject crops and queues reconciliation.

Types

point()

@type point() :: {float(), float()}

Functions

clear(map)

@spec clear(map()) :: :ok

Forgets the stored focal point and requests regeneration of its subject crops.

detect(path)

@spec detect(Path.t()) :: {:ok, point()} | :error

Where the photo at path draws the eye, as {:ok, {x, y}} (fractions of the displayed photo), or :error when detection is unavailable or cannot read it.

detection_available?()

@spec detection_available?() :: boolean()

Whether detection is available (the optional vix package is loaded).

ensure(file, local_path, opts \\ [])

@spec ensure(map(), Path.t(), keyword()) :: point() | nil

The focal point to crop file around, from its original at local_path: the stored one, else a detected one (stored, so the next rendition does not detect again), else nil. Never raises: a photo detection cannot read is cropped at the center.

get(arg1)

@spec get(map()) :: {point(), String.t()} | nil

The focal point stored on file and where it came from, or nil: {{x, y}, "auto" | "manual"}.

put(file, x, y, source, opts \\ [])

@spec put(map(), number(), number(), String.t(), keyword()) ::
  {:ok, point()} | {:ok, :kept} | {:error, :invalid | :stale_source}

Records a focal point for file: x and y between 0 and 1, source "auto" or "manual". A detected point never replaces a manual one ({:ok, :kept}). Only the "focal" key of the metadata changes. A change of point also invalidates generated subject crops and queues reconciliation.

Detected points are accepted only while the file's checksum is unchanged. Pass source_key: when the bytes came from Storage.retrieve_original/1; that original must still belong to the file when the point is recorded.