The .webp format supports not just static images, but also animated images. When I upload an animated .webp, the thumbnails in the web timeline, as well as the previews that are shown after clicking on an image but before zooming, no animation is playing. As soon as I start zooming into the image, the animation starts. This seems to be because the generated thumbnails and previews are just a static image. I have tried switching the preview and thumbnail generator settings from .jpg to .webp, but still there is no animation.
Possible solutions
I've done some research and have come up with some possible solutions, and I would be interested in hearing other's opinions.
To generate image thumbnails and previews, we are using the sharp library. MediaService currently loads the image as raw pixel data into a buffer, and then later passes that buffer again to sharp in order to write it to a file after resizing and converting.
Sharp provides an option to load all frames of an animated image rather than just the first frame, which we could pass in here as animated: true. I have tested this and the buffer then does indeed contain all the frames stacked vertically, and the info object returned from decodeImage then also contains the number of frames or "pages" in the image. Unfortunately, when writing the buffer back to disk, this information is lost and we just end up with a very tall stacked image.
The sharp maintainers are aware of this problem, it is documented in issues https://github.com/lovell/sharp/issues/4092 and https://github.com/lovell/sharp/issues/3236. So one solution would be to just wait until this is resolved upstream, and then add the animated: true flag (along with some additional logic to disable it when the preview format is set to jpg).
Alternatively, we could go for a solution similar to what is currently done for gifs, there we just bypass the generated preview. Either we just check for the mime 'image/webp', or we first compute some kind of isAnimatedImage on the server side for every image and add that property to AssetResponseDto. This would also allow us to load previews instead of the full gif for single-frame gifs.
The OS that Immich Server is running on
Arch Linux
Version of Immich Server
v1.118.2
Version of Immich Mobile App
(i'm only using the web interface)
Platform with the issue
[ ] Server
[X] Web
[ ] Mobile
Your docker-compose.yml content
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
# ports:
# - 2283:2283
depends_on:
- redis
- database
restart: always
labels:
- "traefik.http.routers.whoami.rule=Host(`REDACTED`)"
immich-machine-learning:
container_name: immich_machine_learning
# For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
# file: hwaccel.ml.yml
# service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
redis:
container_name: immich_redis
image: registry.hub.docker.com/library/redis:6.2-alpine@sha256:51d6c56749a4243096327e3fb964a48ed92254357108449cb6e23999c37773c5
healthcheck:
test: redis-cli ping || exit 1
restart: always
database:
container_name: immich_postgres
image: registry.hub.docker.com/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- ./pgdata:/var/lib/postgresql/data
healthcheck:
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
interval: 5m
start_interval: 30s
start_period: 5m
command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
restart: always
volumes:
model-cache:
networks:
default:
name: traefik
external: true
Your .env content
# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables
# The location where your uploaded files are stored
UPLOAD_LOCATION=./library
# The Immich version to use. You can pin this to a specific version like "v1.71.0"
IMMICH_VERSION=v1.118.2
# Connection secret for postgres. You should change it to a random password
DB_PASSWORD=REDACTED
# The values below this line do not need to be changed
###################################################################################
DB_HOSTNAME=immich_postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
REDIS_HOSTNAME=immich_redis
For anyone struggling with the same issue, a quick fix is to just go to your account settings, and then under "App Settings" enable the option "Display original photos"
The bug
The .webp format supports not just static images, but also animated images. When I upload an animated .webp, the thumbnails in the web timeline, as well as the previews that are shown after clicking on an image but before zooming, no animation is playing. As soon as I start zooming into the image, the animation starts. This seems to be because the generated thumbnails and previews are just a static image. I have tried switching the preview and thumbnail generator settings from .jpg to .webp, but still there is no animation.
Possible solutions
I've done some research and have come up with some possible solutions, and I would be interested in hearing other's opinions.
To generate image thumbnails and previews, we are using the sharp library.
MediaService
currently loads the image as raw pixel data into a buffer, and then later passes that buffer again to sharp in order to write it to a file after resizing and converting.Sharp provides an option to load all frames of an animated image rather than just the first frame, which we could pass in here as
animated: true
. I have tested this and the buffer then does indeed contain all the frames stacked vertically, and theinfo
object returned fromdecodeImage
then also contains the number of frames or "pages" in the image. Unfortunately, when writing the buffer back to disk, this information is lost and we just end up with a very tall stacked image.The sharp maintainers are aware of this problem, it is documented in issues https://github.com/lovell/sharp/issues/4092 and https://github.com/lovell/sharp/issues/3236. So one solution would be to just wait until this is resolved upstream, and then add the
animated: true
flag (along with some additional logic to disable it when the preview format is set to jpg).Alternatively, we could go for a solution similar to what is currently done for gifs, there we just bypass the generated preview. Either we just check for the mime 'image/webp', or we first compute some kind of
isAnimatedImage
on the server side for every image and add that property toAssetResponseDto
. This would also allow us to load previews instead of the full gif for single-frame gifs.The OS that Immich Server is running on
Arch Linux
Version of Immich Server
v1.118.2
Version of Immich Mobile App
(i'm only using the web interface)
Platform with the issue
Your docker-compose.yml content
Your .env content
Reproduction steps
Relevant log output
No response
Additional information
No response