Creating a sprite image using ASP.NET
Asked Answered
M

1

7

I'm having a major performance issue. The problem is on one of my websites there is a slider that calls about 180 images. Each one of those 180 images is downloaded by a client browser via an individual url. They are a mixture of gifs and jpg and I'd like to combine them into a single image; preferably a jpg since transparency isn't an issue. The images are stored in a SQL database and are displayed via an MVC Controller. I imagine this sprite could also be created via a MVC Controller as opposed to the more traditional generic ashx handler.

I did some googling and came across a blog post by Scott Hanselman. The post explains how to combine check images and does generally what I want to do. It was written in 2005 so I'm curious if there may be a better way. I've been using ImageResizer on another project. I listened to the podcast by Mr. Hanselman that talks with the founder of the project about resizing images using IIS and .NET. I gleaned from that podcast, and my experience, that image manipulation in .NET and IIS can get weird.

Is it still a good idea to resize and merge images into sprites this way? I don't want a sprite generator, I want an efficient method to combine .gif and jpg into a single image that can be used as a sprite.

Micrometry answered 24/4, 2012 at 4:7 Comment(4)
Before you try the souped up, cutting edge, folded into the fourth-dimension code you'd like one of us to post, how 'bout trying out Scott's solution first, and see if that works out for you?Broglie
Just keep looking on Scott's blog for a more recent whack at the cat: hanselman.com/blog/… Scott Mitchell also has a walkthrough here: dotnetslackers.com/articles/aspnet/… Cheers.Insnare
* I should note that I do not generally condone the whacking of cats.Insnare
Unfortunately I found these before posting the question. What I want to do is lower level than this. Thanks though. :-)Micrometry
N
7

I don't suggest combining everything into a single image, as you'll delay the 'initial appearance' of any images until the entire file downloads. Better to let the visible stuff load ASAP and optimize the rest for overall throughput.

If the images are under 50KB each, for example, it may make sense to combine them as sprite images, but I'd suggest combining, say, 10 at a time. If the images are tiny, like 5KB each, 30 at a time would be reasonable.

You've got a series of bottlenecks here to worry about

  1. HTTP overhead and concurrent connection limitations (sprite images help with this)
  2. Server throughput overhead (solvable with correct disk caching and edge caching)
  3. Browser rendering overhead (Sprites are best for icons and small thumbnails; they shouldn't be gigantic, try to keep it under 1 megapixel).

Joining existing images together and re-compressing in jpeg form can sometimes improve compression, other times it will introduce artifacts. For example, mixing line art and photographs is a bad idea. Jpeg is bad at line art. Use PNG, even PNG-8 if you want. Sometimes you'll find that JPEG at 100% quality ends up smaller than the GIF or PNG version, but most of the time, line art is best stored in PNG form.

If you have IDs for these photos, and plan on going the dynamic route with disk caching, it does simplify your task significantly.

The ImageResizer library will let you 'plug in' to its dynamic pipeline and disk caching system quite easily.

In this case, you'll implement IVirtualImageProvider and IVirtualBitmapFile. See the Gradient plugin for a simple example of generating a bitmap and letting the pipeline handle the rest.

You'll have to define your url syntax and look for it in the FileExists and GetFile methods. Something like /combine-images.ashx?idlist=34,56,79,23&dir=horizontal&width=50&height=50.

Then you'll have to load up each of the images, resize it with the Managed API into a bitmap instance, and draw it on the canvas you've allocated.

Most of your bottleneck will probably be in pulling the images from SQL. If you've got limited RAM on the server, a serial approach might be safer than a parallel one (I.e, get one image at a time from SQL, resize and draw it, dispose data, move on). If your source images are tiny to start with, a multi-threaded apprach might be okay. Just remember you need to make it fast even if it's disk cached, because requests default to timing out after 30 seconds. Done properly, you should be able to serve a 10 image sprite in under 2 seconds with a empty disk cache, 20ms once it's cached.

If this seems a bit overwhelming, I do offer custom plugin development, but there is a queue.

There are a lot of advantages to a 1 file-per-request approach, and it might be worth trying the ImageResizer's disk cache and SqlReader plugins before hopping on the Sprite bandwagon. Not saying it's the wrong approach, but uncached MVC+SQL can add a lot of overhead that might be contributing.

Nagel answered 24/4, 2012 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.