Face editor selection rectangle scales and repositions with zoom, window
resize, and detail panel open/close. Move clientWidth/clientHeight
bindings to the data-viewer-content div so the face editor respects
viewer bounds and does not draw under the detail panel.
Split out from #26636 (adaptive image loading). Leverages the
ContentMetrics extraction from #26310.
Moves face bounding boxes and OCR overlays from viewport-relative
to image-relative coordinates.
New features: zoom with face editor open, zoom with OCR boxes
visible, accurate face hover hit-testing at any zoom level.
Bug fixes: face tagging on stacked assets, faces loading when browsing
stacks, face editor auto-close on last face deletion, zoomTarget was
null, disablePointer option name mismatch.
Replace ImageManager with a new AdaptiveImageLoader that progressively
loads images through quality tiers (thumbnail → preview → original).
New components and utilities:
- AdaptiveImage: layered image renderer with thumbhash, thumbnail,
preview, and original layers with visibility managed by load state
- AdaptiveImageLoader: state machine driving the quality progression
with per-quality callbacks and error handling
- ImageLayer/Image: low-level image elements with load/error lifecycle
- PreloadManager: preloads adjacent assets for instant navigation
- AlphaBackground/DelayedLoadingSpinner: loading state UI
Zoom is handled via a derived CSS transform applied to the content
wrapper in AdaptiveImage, with the zoom library (zoomTarget: null)
only tracking state without manipulating the DOM directly.
Also adds scaleToCover to container-utils and getAssetUrls to utils.
* Enable OpenVINO CPU acceleration in Immich
* Remove unnecessary debug log
* Removing checking for device_ids for openvino since cpu will always be available
* Find OpenVINOExecutionProvider index instead of assuming index 0
* Fix openvino tests
* Fix failing test mock. OpenVINO expects provider options, but cuda provide doesn't so use that for mocked tests.
* Support empty provider options in OrtSessions in which case ONNXRuntime will use its own defaults
* Use OpenVINOExecutionProvider for test_sets_provider_options_kwarg
* fix mock
* simplify
* unused variable
---------
Co-authored-by: Aleksander <pejcic@adobe.com>
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
* Fix opus handling as accepted audio codec in transcode policy
Fix the issue when opus is among accepted audio codecs in transcode policy
(which is default) but it still triggers transcoding because the codec name
from ffprobe (opus) does not match `libopus` literal in Immich.
Make a distinction between a codec name and encoder:
- codec name: switch to `opus` as the audio codec name. This matches what ffprobe
returns for a media file with opus audio.
- encoder: continue using the `libopus` encoder in ffmpeg.
* Add unit tests for accepted audio codecs and for libopus encoder
* Add db migration for ffmpeg.targetAudioCodec opus
* backward compatibility
* tweak
* noisy logs
* full mapping
* make check happy
* mark deprecated
* update api
* indexOf
---------
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
* fix(mobile): correct local asset dimensions
We are constraining the size of videos so that they play nicely with
hero animations, and don't stretch in weird ways. This however caused a
regression as we are not account for local assets on Android which have
un-oriented dimensions.
* post-orientation width and height in local sync
* migration
* no need to handle it in asset viewer
---------
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
* feat(android): enhance playback style detection using MIME type
* feat(android): improve playback style detection for GIF and WebP formats
* fix(android): make playback style detection faster
* refactor(android): simplify XMP reading logic for API 29 and below
* update playback style detection documentation
* use DefaultImageHeaderParser instead of all available ones for webp playbackStyle type detection
Search results use a different provider than the main timeline, and they
appear appear to have diverged a bit. This means that assets can
sometimes look wrong or different in search compared to the main
timeline or albums.
The background of the photo view does not extend below the height of the
viewport, and so the asset details fade in over black with the photo
view, and the standard surface colour scheme of the scaffold for the
rest. This leads to a janky animation. We can't change the background of
the scaffold to black, as it in turn makes the iOS bouncing scroll
physics cut off incorrectly. The best fix is to remove background
decoration from the photo view, and defer to the parent to colour the
background.
Co-authored-by: Alex <alex.tran1502@gmail.com>
Search results are replaced with a spinner when loading the next page,
which is quite jarring. Search results now remain visible when loading
the next page with a spinner at the bottom. The next page also loads
sooner, which makes it feel a lot smoother.
Co-authored-by: Alex <alex.tran1502@gmail.com>
In order to scroll smoothly without interfering with the gesture
detector on the photo view, we have an offstate scroll view which we
defer all drags to, and then forward scroll offsets to the real scroll
controller. This works well, but it can be simpler. Instead, we can
create a custom scroll controller on a scroll view with never scrollable
physics, and then forward drag events to that, bypassing the need for a
proxy scroll controller.
Co-authored-by: Alex <alex.tran1502@gmail.com>
* feat(web): when hovering over a face already deteced, display the bounding box also shown when hovering over the person in the details-pane.
* prevent lint error
* fix unused var
Add `name` to all vitest configs matching CI job buckets (server:unit,
server:medium, cli:unit, web:unit, e2e:server, e2e:maintenance) so they
appear as filterable @tags in the Vitest VSCode extension.
Fix `root` in server vitest configs to use an absolute path derived from
`import.meta.url` instead of `'./'`, which resolved relative to the config
file directory (`server/test/`) rather than `server/`, causing test
discovery to fail in the Vitest VSCode extension.
Consolidate video state into a single asset-scoped provider, and reduce
dependency on global state generally. Overall this should fix a few
timing issues and race conditions with videos specifically, and make
future changes in this area easier.