Search code examples
node.jsimage-processingfile-uploadserver-sideresource-management

Resize image when uploading to server or when serving from server to client?


My website uses many images. On a weak day users will upload hundreds of new images. I'm trying to figure out what is the best-practice for manipulating sizes of images.

This project uses Node.js with gm module for manipulating images, but I don't think this question is node or gm specific.

I came up with several strategies, but I can't make a decision as to which is the best, and I am not sure if I am missing an obvious best-practice strategy.

Please enlighten me with your thoughts and experience.

Option 1: Resize the file with gm on every client request.

Option 1 pros:

  1. If I run gm function every time I serve a file, I can control the size, quality, compression, filters and so on whenever I need it.

  2. On the server I only save 1, full quality - full size version of the file and save storage space.

Option 1 cons:

  1. gm is very resource intensive, and that means that I will be abusing my RAM for every single image server to every single client.

  2. It means I will be always working from a big file, which makes things even worse.

  3. I will always have to fetch the file from my storage (in my case S3) to the server, then manipulate it, then serve it. It seems like it would create redundant bandwidth issues.

Option 2: resize the file on first upload and keep multiple sizes of the file on the server.

Option 2 pros:

  1. I will only have to use gm on uploads.

  2. Serving the files will require almost no resources.

Option 2 cons:

  1. I will use more storage because I will be saving multiple versions of the same file (i.e full, large, medium, small, x-small) instead of only one version.

  2. I will be limited to using only the sizes that were created when the user uploaded their image.

  3. Not flexible - If in the future I decide I need an additional size version (x-x-small for instance) I will have to run a script that processes every image in my storage to create the new version of the image.

Option 3: Use option 2 to only process files on upload, but retain a resize module when serving file sizes that don't have a stored version in my storage.

Option 3 pros:

  1. I will be able to reduce resource usage significantly when serving files in a selection of set sizes.

Option 3 cons:

  1. I would still take more storage as in option 2 vs option 1.

  2. I will still have to process files when I serve them in cases where I don't have the file size I want

Option 4: I do not create multiple versions of files on upload. I do resize the images when I serve them, BUT when ever an image size was requested, this version of the file will be saved in my storage and for future requests I will not have to process the image again.

Option 4 pros:

  1. I will only use storage for the versions I use.

  2. I could add a new file size when ever I need, it will be automatically created on a need-basis if it doesn't already exists.

  3. Will use a lot of resources only once per file

Option 4 cons:

  1. Files that are only accessed once will be both resource intensive AND storage intensive. Because I will access the file, see that the size version I need doesn't exist, create the new file version, use the resources needed, and save it to my storage wasting storage space for a file that will only be used once (note, I can't know how many times files will be used)
    1. I will have to check if the file already exists for every request.

So,

  1. Which would you choose? Why?

  2. Is there a better way than the ways I suggested?


Solution

  • Solution highly depends on the usage you have for your resources. If you have an intensive utilisation then option 2 is from far the better. If not, option 1 could work nicely also.

    From a qualitative point of view I think option 4 is the best of course. But for a question of simplicity and automation, I think option 2 is way better.

    Because simplicity matter, I suggest to mix the option 2 and 4 : you will have a list of size (e.g. large,medium,small), but will not process them on upload but when requested as in option 4.

    So that in the end, in the worst case you will arrive to the option 2 solution.

    My final word would be that you should also use the <img> and/or <canvas> object in your website to perform the final sizing, so that the small computation overhead is not done on the server side.