GeotrekCE / Geotrek-admin

Paths management for National Parks and Tourism organizations
https://geotrek.fr
BSD 2-Clause "Simplified" License
131 stars 75 forks source link

[API] Images optimization #3463

Open dtrucs opened 1 year ago

dtrucs commented 1 year ago

To optimize the images of Geotrek Rando (or of another service using the GTA API), there are several projects that can be carried out.

Let's take the example of an API return from the field attachments of type: "image", from which we have removed the keys that are not necessary for our needs:

{
  "type": "image",
  "author": "Office de tourisme Pays des Écrins",
  "thumbnail": "https://geotrek-admin.ecrins-parcnational.fr/media/paperclip/trekking_trek/962618/canva-photo-editor-7_resultat.png.400x0_q85.png",
  "legend": "Vue sur la vallée de Vallouise",
  "url": "https://geotrek-admin.ecrins-parcnational.fr/media/paperclip/trekking_trek/962618/canva-photo-editor-7_resultat.png",
}

Different image sizes:

The more different image sizes are offered, the more it is possible to optimise by loading the necessary one into the browser. However, this requires more work on the part of the backend to crop/resize and serve these images.

Today only the source image (url) and a 400px wide resized image (thumbnail) are offered. But for the optimal need of GTR, we need more formats to satisfy all situations (different components and different screen sizes):

ex-screensize

For the same image, we would need:

{
  "images": [
    {
      "250x300": {
       "src": "://mysite.com/image-250x300.png"
      },
      "300x200": {
        "src": "://mysite.com/image-300x200.png"
      },
      "640x300": {
        "src": "://mysite.com/image-640x300.png"
      },
      "768x550": {
        "src": "://mysite.com/image-768x550.png"
      },
      "1050x550": {
        "src": "://mysite.com/image-1050x650.png"
      }
    }
  ]
}

Some screens offer a pixel density multiplied by 2. For these screens we can offer better quality images:

{
    "250x300": {
       "src": "://mysite.com/image-250x300.png",
       "srcx2": "://mysite.com/image-500x600.png"
    }
}

Some browsers can interpret compressed images in .webp format:

{
    "250x300": {
       "src": "://mysite.com/image-250x300.png",
       "srcx2": "://mysite.com/image-500x600.png",
       "webp": "://mysite.com/image-250x300.webp",
       "webpx2": "://mysite.com/image-500x600.webp"
    }
}

Explicitly define image sizes:

With sizes the frontend can define the size and ratio of the images and avoid a cumulative layout shift.

{
    "250x300": {
       "size": {
         "width": "250px",
         "height": "300px"
       },
       "src": "://mysite.com/image-250x300.png",
       "srcx2": "://mysite.com/image-500x600.png",
       "webp": "://mysite.com/image-250x300.webp",
       "webpx2": "://mysite.com/image-500x600.webp"
    }
}

Define the hotspot of the image:

Some images are cropped for thumbnails and the main subject is not necessarily in the centre of the image, it would be interesting to be able to define a hotspot in the backoffice when uploading the image, for example:

image

Even if the hotspot + crop is done on the backend side, it may be necessary to expose it in the API:

{
    "250x300": {
       "hotspot": {
          "left": "50%",
          "top": "50%"
        },
       "size": {
         "width": "250px",
         "height": "300px"
       },
       "src": "://mysite.com/image-250x300.png",
       "srcx2": "://mysite.com/image-500x600.png",
       "webp": "://mysite.com/image-250x300.webp",
       "webpx2": "://mysite.com/image-500x600.webp"
    }
}
camillemonchicourt commented 1 year ago

I am not sure we should crop and use hotspot of images. I think I would just very simpler and always display the full image, without cropping it, as suggested here - https://github.com/GeotrekCE/Geotrek-rando-v3/issues/803.

There is also another issue about image size when displayed on fullscreen - https://github.com/GeotrekCE/Geotrek-rando-v3/issues/454

Also discussed on https://github.com/GeotrekCE/Geotrek-admin/issues/3059

camillemonchicourt commented 1 year ago

Also, I am not sure, we should generate all the image sizes required by Geotrek-rando-v3 or other, when uploading images. Usages can change. I would but rather just keep the original image and be able to resize it on demand. Example : On client side (Geotrek-rando-v3), ask for https://server/image-file.jpg?h=500&w=500 The image would generated server side (with Pillow or other) the first time it is requested and kept on server for the next time it is requested.

marcantoinedupre commented 1 year ago

Example : On client side (Geotrek-rando-v3), ask for https://server/image-file.jpg?h=500&w=500

I think this could be too easily abused. Anyone could flood the server in terms of CPU and disk space by requesting a lot of resizing. To adapt to evolving use cases I'd suggest to replace property names : instead of "250x300" use "small" or something like that. Since we will keep the original upload we could decide to change what are the dimensions of "small" and resize all small images.