j.heidt

Avoid 287at all costs
posts - 14, comments - 11, trackbacks - 1

Wednesday, December 12, 2007

CSS SpriteGen Source

I've finally managed to get everything straightened out between my computer and my web server. And, as promised, I have code for everyone. I plan on setting up an online service to do this on my server, but I decided that having some source code and a blog update is better than none. So, the basic architecture of the sprite generator is broken down as such:

The main sprite generator class has snap-in points for classes to define behavior for the following:

ImageLoader: The image loader is responsible for returning a group of images. Ones in this code release are the ZipFileLoader and the DirectoryLoader. They return images from a zipfile, and a directory, respectively (Surprise!). Future ImageLoaders ideas are some type of Webpage image loader, and also a DatabaseImageLoader, which would understand binary data in a database.

ImageRenderer: This class is simply responsible for rendering the input image stream into a System.Bitmap. This is used before packing to determine a number of things, but primarily, if the image is a valid image, if it meets the source image restrictions,  and the dimensions of the image.

Packer: This class does the heavy lifting for image positioning & packing. I have implemented the packer in a generic manner, so if you need a class that knows how to binpack, feel free to use this.

OutputImageRenderer: Takes the final packed rectangle data, and loads the bitmap for the associated rectangle for it from the ImageLoader, and finally renders the whole bunch to an image. Having a separate class for this allows me to put watermarks or have funny image rendering rules. This is different than the ImageRenderer because this class renders out the final image, it tends to call into the ImageRenderer for each image, so you see how they are quite different.

And the HtmlCssGenerator, which takes the list of packed images and generates HTML and CSS markup for it. This is mostly just a string template dumper right now. This code is what I'm currently cleaning up, so pay no mind if its a bit ragged.

Attached is the current source, released under the MIT license. Basically, do whatever you want with it, but if you use it let me know, I would love to hear about what you ended up doing with it.

Here's some example code I've been using to test the functionality:

ConsoleTraceListener c = new ConsoleTraceListener();
c.TraceOutputOptions = TraceOptions.DateTime;
Trace.Listeners.Add(new ConsoleTraceListener());

const int OneMeg = 1048576;
InputImageFormats extensions = InputImageFormats.Jpeg | InputImageFormats.Gif | InputImageFormats.Png;

// load the base processor.
SpriteProcessor processor = new SpriteProcessor();

// load the default image renderer.
DefaultRenderer renderer = new DefaultRenderer();

const int Packer_Max_Width = 1600;
const int Packer_Max_Height = 1200;
bool UseZip = false;

IImageLoader imgLoader;
if (UseZip) { // load the zip file loader
    const string zipFile = @"C:\Users\jake\Pictures\SomePictures.zip";
    Stream zipFileStream = new FileStream(zipFile, FileMode.Open, FileAccess.Read, FileShare.Read, 2048);
    ZipFileLoader loader = new ZipFileLoader(extensions, (100 * OneMeg), zipFileStream);
    imgLoader = loader;
} else {
    const string directory = @"C:\Users\jake\Libraries\Silk Icons";
    DirectoryLoader loader = new DirectoryLoader(directory, extensions, true);
    imgLoader = loader;
}

imgLoader.MaximumInputFileSize = OneMeg;
imgLoader.MaximumInputImageHeight = 300;
imgLoader.MaximumInputImageWidth = 300;
imgLoader.MaximumProcessedCount = 10000;
imgLoader.MaximumResultCount = 10000;

// load the packer
Packer<IImageData, string> packer = new Packer<IImageData, string>(Packer_Max_Width, Packer_Max_Height);

// load the output renderer
OutputRenderer output = new OutputRenderer(@"C:\Users\jake\Desktop");

// cssgen.
HtmlCssGenerator gen = new HtmlCssGenerator();

// setup the processor
processor.ImageRenderer = renderer;
processor.Loader = imgLoader;
processor.Packer = packer;
processor.OutputRenderer = output;

Trace.TraceInformation("Processor:Initializing...");
processor.Initialize();
Trace.TraceInformation("Processor:Initializing Complete");

Trace.TraceInformation("Processor:Loading...");
processor.Load();
Trace.TraceInformation("Processor:Loading Complete, Image loader found {0} images.", processor.SourceImages.Count);

Trace.TraceInformation("Processor:Packing...");
processor.Pack();
Trace.TraceInformation("Processor:Packing Complete, Packed {0} images.", processor.PackedItems.Count);

Trace.TraceInformation("Processor:Rendering Output...");
processor.Render();
Trace.TraceInformation("Processor:Rendering Output Complete");


Console.WriteLine();
Console.WriteLine("----- Complete, Press Enter To Continue -----");
Console.ReadLine();

posted @ Wednesday, December 12, 2007 8:57 PM | Feedback (0) |

Powered by: