Most efficient way of saving images and sending them to client browser

azureblobimage manipulationimage processing

I'm building an app where users list items for sale and they can include up to five photos for each item. I'm using Azure Blob storage for storing the images.

In my app, I'll be displaying these images in several different ways and sizes. I'll show them as thumbnails, as roughly 250px in width and full size, depending on the page on which they are being displayed.

I'd like to know best practice for storing these images and sending them to the client. I have a couple choices. I could store just the single image, and then retrieve and resize it, depending on how it's going to get displayed, on the server before sending it to the client. Or, I could store several copies of each image, each with the appropriate size that will be required in the client pages.

I'm leaning towards the first option where I just save the single original copy, resize it on the server and then send it to the client. I have no experience with this sort of thing so I'm not certain the best approach, or if there are others.

Best Answer

There are couple optimizations that can be done:

  1. After retrieving the images from the blobs, cache it into memory, depending on hit frequency. If the amount of images is very important, consider using redis as a L2 cache provider (now available on Azure). If the web server has to support a massive amount of hits, and the images can be publicly available, I recommend to delegate Images transfers to the azure CDN, to get a (very) low latency.
  2. Set the Cache-Control http header to an appropriate value. This will greatly limit the amount of round-trip per client
  3. If the images are meant to be viewed at multiple sizes, consider sending only two versions: Thumbnails and HD. Then you can easily integrate the image to any size using the CSS3 background-size:contain; property, which gives great results.
  4. In order to limit client/server round-trips, I would advise to send your images grouped. Using CSS3, you can inline multiple images in a single css file. Here is a method I wrote that merge images from a directory, as a single CSS string:

    private static string images2css(string directory = "~/Images")
    {
        StringBuilder css = new StringBuilder();
        foreach (string f in Directory.GetFiles(System.Web.Hosting.HostingEnvironment.MapPath(directory)).Where(x => x.EndsWith(".png") || x.EndsWith(".jpg") || x.EndsWith(".jpeg")))
        {
            var img = Image.FromFile(f);
            byte[] raw = File.ReadAllBytes(f);
            string name = Path.GetFileNameWithoutExtension(f);
            string ext = Path.GetExtension(f).Substring(1);
    
            css.AppendFormat(".img-{0}{{", name.Replace('_', '-'));
            css.AppendLine("background-color: transparent; background-repeat: no-repeat; background-position: left top;");
            css.AppendLine(string.Format("background-image: url(data:image/{1};base64,{0});", Convert.ToBase64String(raw), ext));
            css.AppendLine(string.Format("padding-left: {0}px !important; min-height: {1}px;", img.Width + 5, img.Height));
            //   css.AppendLine("background-size: contain;");
            css.AppendLine("}");
            img.Dispose();
        }
    
        return css.ToString();
    }
    

Shouldn't be too much work adapting it to fetch the images from an Azure Blob. You could also save the css string back to another blob with Gzip compression, and make it available to the cdn.

Overall, there are 3 main parameters to consider to choose the best strategy:

  • Are there a lot of Images? (no: L1 cache, yes: L2 cache)
  • Does the front server has to handle a massive amount of hits? (yes: the front server must not send images. Best option is CDN)
  • Does a page displays the same set of images (=> group images in one file), or the combination always different? (=> L2 cache or CDN)
Related Topic