I'm working on an application with a database containing many recipes. The API is written in Django (with Django REST Framework) and frontend in React.
Each recipe is assigned a high-quality image. In React application, the user can see all the recipes with their images in a list view. The problem is that they take too long to load. The solution I came up with is storing two images for each meal. One is the high-resolution image which is only loaded in detail view, and a thumbnail which is simply a smaller version of that picture that shows in the list view.
How would you go about this? Is it the optimal solution? Or is there a way to downscale the image already in the frontend, without having to store two images in the database?
3 Answers
Having multiple different resolution images is a very good idea. Perhaps 2, perhaps more, in your use case probably those 2.
The problem with downscaling on the fly is that you have to:
- Wait for network capacity to give you the images from the database
- Wait for JPEG decompression to decompress each high-resolution image
- Wait for resizing algorithm to make them into lower resolution
The first takes network bandwidth, the remaining two take CPU time. I'm certain that some of those three is your bottleneck. If you downscale images in the frontend, all of those are repeatedly taking resources.
If you already know what resolution you need and the requirements won't change, store just those resolutions. If you don't, then it's possible to store powers of two, e.g. 2048x2048, 1024x1024, 512x512, 256x256, 128x128.
The biggest issue you will run into is bandwidth. Quite simply larger images require more bytes than smaller images. Having a down-scaled image for your listing helps save that bandwidth until a user actually picks a recipe to open. You don't need the high resolution photo at that time. The downside is that you are storing more bytes in your database. Many times the bandwidth is worth it.
You have a couple of options available to you:
- If you store your images in a cloud blob store, most cloud providers allow you to create an asynchronous job to downscale and store the smaller image without changing your code
- If you store images in a database, you have to build that infrastructure yourself
- On the upload side, have the client perform the image scaling and upload both images at that time
Bottom line is that you need to process the photos, the only difference being the mechanism you choose to do it. If you have something in place to asynchronously generate thumbnails, then you do need a placeholder image that is displayed until the thumbnail is ready.
There is the concept of progressive image encoding. This essentially splits the image into layers, where each layer contains additional details. This can allow a lower quality image to be downloaded first, and the additional detail downloaded at some later time. This could save a bit of data compared to using a separate thumbnail. This technique can be a major benefit you want to quickly display a full resolution image at lower quality, adding more details as more data have time to download.
But it might require a more complex system, and some components might not support progressive encoding. So using a separate thumbnail will probably be easier. And if the size ratio between the full resolution image and thumbnail is large, then the additional overhead will be small.
-
1If the page contains 50 thumbnails, I'm pretty sure the software to display that page such as a web browser only fetches few thumbnails at a time and when this limited number of thumbnails have been downloaded, proceeds to download the next. I don't believe any software creates 50 connections to the server, which would be required to display all images first at low resolution and then at high resolution.– juhistJun 20, 2022 at 17:38
srcset
, see here. Regardless, you should have more than one size available, it's not a bad thing. Also gzip..