Caching bitmaps in the HttpContext.Current.Cache

I was working on a website that is generating images on the fly. Generating these images takes some time and therefore they needed to be cached.
So I wrote this small piece of code, just for this:


public static void Cache(Bitmap bmp, String key)
{
  HttpContext.Current.Cache.Insert(key, bmp, null,
    System.Web.Caching.Cache.NoAbsoluteExpiration,
    System.Web.Caching.Cache.NoSlidingExpiration,
    System.Web.Caching.CacheItemPriority.Normal, null);
}
 
public static Bitmap Fetch(String key)
{
  return HttpContext.Current.Cache.Get(key) as BitmapCache;
}

That was easy and straight forward, however this was one of these cases where things are not what they seem to be. Generating the image went without any issue and showed on the webpage. However, getting the image from the cache did not return an image but an error message in stead. The error message was ArgumentException: Parameter is not valid.

When trying to view the properties of the bitmap in debug mode, all of the properties showed the same error in stead of their actual value. After scratching my head a few times I found why, the bitmap was disposed. The above code puts a reference to the bitmap in the cache, so when the bitmap gets disposed it is not longer accessible from the cache. I first thought of creating a copy of the bitmap and put that in the cache, but then I found a much nicer solution on the web: Store the bitmap as a byte array.

Now the code for caching the bitmap looks like


public static void Cache(Bitmap bmp, String key)
{
  //Store the image as a byte array. The bitmap its self maybe disposed
  //and this will retrieve a disposed image from the chache.
  using (var ms = new MemoryStream())

  bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
  HttpContext.Current.Cache.Insert(key, new BitmapCache(ms.ToArray()), null,
      System.Web.Caching.Cache.NoAbsoluteExpiration,
      System.Web.Caching.Cache.NoSlidingExpiration,
      System.Web.Caching.CacheItemPriority.Normal, null);
  }

public static Bitmap Fetch(String key)
{
  byte[] bitmapAsArray= HttpContext.Current.Cache.Get(key) as BitmapCache;
  Bitmap bmp = null;
  try
  {
    using (var ms = new MemoryStream((byte[])bc.bitmapAsArray))
    {
      bmp = Bitmap.FromStream(ms) as Bitmap;
    }
  catch(Exception)
  {
    return null;
  }
  return bmp;
}

and this works everytime. There is a slight overhead in transforming the byte[] to a bitmap, but this is much less then generating the bitmap everytime. When you want to output the image direct you could even stream the byte[] directly and thus avoiding the overhead of transforming it to the bitmap.

Leave a Reply

Your email address will not be published. Required fields are marked *

* Copy This Password *

* Type Or Paste Password Here *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>