immich-app / immich

High performance self-hosted photo and video management solution.
https://immich.app
GNU Affero General Public License v3.0
49.46k stars 2.61k forks source link

Thumbnails and previews for animated .webp are static #13724

Open Pascal-So opened 4 hours ago

Pascal-So commented 4 hours ago

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 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

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

Reproduction steps

  1. Upload an animated .webp
  2. Wait for background jobs to finish
  3. Click the image in the timeline
  4. Note that the image is not animated
  5. Zoom in slightly
  6. Note that the animation starts now

Relevant log output

No response

Additional information

No response

Pascal-So commented 3 hours ago

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"