j.heidt

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

Wednesday, August 13, 2008

Fun 2.0 list methods

I was working on some code at work that was using the 2.0 framework and COM interop, and in the course of adding enumerator capability to the old COM code, I worked up a quick Lists.cs static class that does some useful things on IEnumerable<T> classes.

The methods are heavily inspired from the MooTools Array API

/// <summary>
/// Static helper functions for dealing with enumerable items. 
/// The design of these helper methods was inspired in part by the mootools array library.
/// </summary>
public static class Lists {
    /// <summary>
    /// Calls a the provided function for each element in the list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    public static void Each<T>(IEnumerable<T> list, Action<T> func) {
        foreach (T item in list) {
            func(item);
        }
    }

    /// <summary>
    /// Whiles the specified list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="condition">The condition.</param>
    /// <param name="func">The func.</param>
    public static void While<T>(IEnumerable<T> list, Predicate<T> condition, Action<T> func) {
        foreach (T item in list) {
            if (!condition(item))
                return;
            func(item);
        }
    }

    /// <summary>
    /// Returns true if every element in the list satisfies the provided testing function. 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    /// <returns></returns>
    public static bool Every<T>(IEnumerable<T> list, Predicate<T> func) {
        bool called = false;
        foreach (T item in list) {
            called = true;
            if (!func(item)) {
                return false;
            }
        }
        return called;
    }

    /// <summary>
    /// Creates a new list with all of the elements of the list for which the provided filtering function returns true. 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    /// <returns></returns>
    public static IEnumerable<T> Filter<T>(IEnumerable<T> list, Predicate<T> func) {
        foreach (T item in list) {
            if (func(item)) {
                yield return item;
            }
        }
    }

    /// <summary>
    /// Creates a new list with all of the elements of the source list which are not the default for the list item type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <returns></returns>
    public static IEnumerable<T> Clean<T>(IEnumerable<T> list) {
        foreach (T item in list) {
            if (!Equals(item, default(T))) {
                yield return item;
            }
        }
    }

    /// <summary>
    /// Returns a list with the results of calling a provided function on every element in the source list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    /// <returns></returns>
    public static IEnumerable<T> Map<T>(IEnumerable<T> list, Converter<T, T> func) {
        foreach (T item in list) {
            yield return func(item);
        }
    }

    /// <summary>
    /// Returns a list with the results of calling a provided function on every element in the source list.
    /// </summary>
    /// <typeparam name="TInput">The type of the input.</typeparam>
    /// <typeparam name="TOutput">The type of the output.</typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The converter function.</param>
    /// <returns></returns>
    public static IEnumerable<TOutput> Convert<TInput, TOutput>(IEnumerable<TInput> list, Converter<TInput, TOutput> func) {
        foreach (TInput item in list) {
            yield return func(item);
        }
    }

    /// <summary>
    /// Returns true if at least one element in the source list satisfies the provided testing function.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    /// <returns></returns>
    public static bool Some<T>(IEnumerable<T> list, Predicate<T> func) {
        foreach (T item in list) {
            if (func(item)) {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// Returns a list of key-value pairs based on the list of keys passed in and the items in the source list.
    /// </summary>
    /// <typeparam name="K">The Key type</typeparam>
    /// <typeparam name="V">The Value type</typeparam>
    /// <param name="keys">The list of keys.</param>
    /// <param name="list">The list of values.</param>
    /// <returns></returns>
    public static IEnumerable<KeyValuePair<K, V>> Link<K, V>(IEnumerable<K> keys, IEnumerable<V> list) {
        using (var keyIterator = keys.GetEnumerator()) {
            using (var valueIterator = list.GetEnumerator()) {
                while (keyIterator.MoveNext() &&
                       valueIterator.MoveNext()) {
                    yield return new KeyValuePair<K, V>(keyIterator.Current, valueIterator.Current);
                }
            }
        }
    }

    /// <summary>
    /// Tests the list for the presence of an item.
    /// </summary>
    /// <typeparam name="T">The item types in the list, this type must be equatable to itself</typeparam>
    /// <param name="list">The list.</param>
    /// <param name="item">The item.</param>
    /// <returns>
    ///     <c>true</c> if the specified list contains the item; otherwise, <c>false</c>.
    /// </returns>
    public static bool Contains<T>(IEnumerable<T> list, T item) where T : IEquatable<T> {
        foreach (T val in list) {
            if (Equals(val, item)) {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// Extends a list with all the items of another list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="additions">The additions.</param>
    /// <returns></returns>
    public static IEnumerable<T> Extend<T>(IEnumerable<T> list, params IEnumerable<T>[] additions) {
        foreach (T item in list) {
            yield return item;
        }
        foreach (IEnumerable<T> exList in additions) {
            foreach (T item in exList) {
                yield return item;
            }
        }
    }
}
 
And here is some of the unit test code I did to explain some of the methods if they aren't clear:
 
[TestFixture]
public class ListsTests {

        public string[] FirstNames;
        public string[] LastNames;

        [TestFixtureSetUp]
        public void Init() {
            FirstNames = new[] {"jake", "chris", "jason", "bass", "brian", "russ"};
            LastNames = new[] {"heidt", "oliver", "torres", "bassalino", "dorry", "guzetta"};
        }

        [Test]
        public void Clean() {
            string[] clean_list = new[] {null, null, "some", "strings up in this", null};
            int itemsReturned = 0;
            foreach (string x in Lists.Clean(clean_list)) {
                Assert.IsNotNull(x);
                itemsReturned++;
            }

            Assert.IsTrue(itemsReturned == 2);
        }

        [Test]
        public void Contains() {
            Assert.IsTrue(Lists.Contains(FirstNames, "jake"));
            Assert.IsTrue(Lists.Contains(FirstNames, "chris"));
            Assert.IsTrue(Lists.Contains(FirstNames, "jason"));
            Assert.IsTrue(Lists.Contains(FirstNames, "bass"));
            Assert.IsTrue(Lists.Contains(FirstNames, "brian"));
            Assert.IsTrue(Lists.Contains(FirstNames, "russ"));
            Assert.IsFalse(Lists.Contains(FirstNames, "RUSS"));
        }

        [Test]
        public void Each() {
            int firstNamesWithEvenLetters = 0;
            Lists.Each(FirstNames, delegate(string x) {
                                       if (x.Length % 2 == 0) {
                                           firstNamesWithEvenLetters++;
                                       }
                                   });

            Assert.IsTrue(firstNamesWithEvenLetters == 3); // jake, bass, russ
        }

        [Test]
        public void Every() {
            /* test that each name contains a vowel, using Lists.Every */
            Assert.IsTrue(
                Lists.Every(FirstNames, delegate(string x) { return x.IndexOfAny("aeiou".ToCharArray()) > 0; // contains a vowel
                                        })
                );
        }

        [Test]
        public void Extend() {
            int targetCount = 0;
            int extendCount = 0;

            IEnumerable<string> fNames = FirstNames;
            IEnumerable<string> lNames = LastNames;
            foreach (string name in fNames) {
                targetCount++;
            }
            foreach (string name in lNames) {
                targetCount++;
            }


            IEnumerable<string> bothNameParts = Lists.Extend(fNames, lNames);
            foreach (string name in bothNameParts) {
                extendCount++;
            }

            Assert.IsTrue(targetCount == extendCount);
        }

        [Test]
        public void Filter() {
            IEnumerable<string> evenNames = Lists.Filter(FirstNames, delegate(string x) { return x != null && x.Length % 2 == 0; });
            foreach (string name in evenNames) {
                Trace.WriteLine(string.Format(".Filter -> name: {0}", name));
                Assert.IsNotNull(name);
                Assert.IsTrue(name.Length % 2 == 0);
            }
        }

        [Test]
        public void Link() {
            IEnumerable<KeyValuePair<string, string>> firstLastNameDict = Lists.Link(FirstNames, LastNames);
            foreach (KeyValuePair<string, string> pair in firstLastNameDict) {
                Assert.IsNotNull(pair);
                Assert.IsNotNull(pair.Key);
                Assert.IsNotNull(pair.Value);
                if (pair.Key == "jake") {
                    Assert.IsTrue(pair.Value == "heidt");
                }
                if (pair.Key == "russ") {
                    Assert.IsTrue(pair.Value == "guzetta");
                }
            }
        }

        [Test]
        public void Map() {
            // convert/format each item in the source list to an upper case string.
            IEnumerable<string> upperCaseName = Lists.Map(FirstNames,
                                                          delegate(string x) { return x.ToUpper(); }
                );

            Regex rxUpperCaseOnly = new Regex("^[A-Z ]+$"); // regex test for upper case letters and spaces only
            foreach (string name in upperCaseName) {
                Assert.IsNotNull(name);
                Assert.IsTrue(rxUpperCaseOnly.IsMatch(name));
            }
        }

        [Test]
        public void Some() {
            Assert.IsTrue(Lists.Some(FirstNames, delegate(string x) { return x.Contains("eidt"); }));
        }

        [Test]
        public void Example() {

        }
    }

posted @ Wednesday, August 13, 2008 4:17 PM | Feedback (0) |

Friday, April 25, 2008

An Interesting Discovery on Enums

I have been sandboxing with the 3.5 features a bit, when I came across something that has been around since 2.0 that surprised me. I was using an interface that I had created a while ago, IKeyed<K>, a generic interface that lets me declare that an item can be distinguished from other items of its type, or other items of it's key type.

Nothing groundbreaking here:

/// <summary>
/// A class that impliments IKeyed declares that its identity can be assured against other items
/// in its scope that are also keyed.
/// </summary>
/// <typeparam name="KeyType">The type of the key.</typeparam>
public interface IKeyed<KeyType> : IEquatable<KeyType>, IEquatable<IKeyed<KeyType>> where KeyType : IEquatable<KeyType>
{
    /// <summary>
    /// Gets a value indicating whether this instance's key is set.
    /// </summary>
    /// <value>
    ///     <c>true</c> if this instance is key set; otherwise, <c>false</c>.
    /// </value>
    bool IsKeySet { get; }

    /// <summary>
    /// Gets the key that uniquely identifies this class in its scope.
    /// </summary>
    /// <value>The key.</value>
    KeyType Key { get; }
}

Well, so far so good. I have implemented IKeyed on many classes without a problem. Now let's say I want to toss an Enum into the mix, for example:

public enum ProcessStatus
{
    Unknown,
    Uninitialized,
    Initializing,
    Initialized,
    Processing,
    Completed,
    Fault    
}

Already, again, nothing huge here. Just standard issue stuff. Here's where the problem crept in:

I wanted to create a class that was keyed against the ProcessStatus Enumeration

public class ProcessStatusNotifier : IKeyed<ProcessStatus>
{
    ProcessStatus _Status = ProcessStatus.Unknown;

    #region Object Overrides
    public override bool Equals(object obj) {
        if(obj is ProcessStatusNotifier) { return ((ProcessStatusNotifier)obj).Key.Equals(Key); }
        return base.Equals(obj);
    }

    public override int GetHashCode() {
        return Key.GetHashCode();
    }
    #endregion

    #region IKeyed<ProcessStatus> Members
    public bool IsKeySet {
        get { return true; }
    }
    public ProcessStatus Key {
        get { return _Status; }
    }
    #endregion

    #region IEquatable<ProcessStatus> Members
    public bool Equals(ProcessStatus other) {
        return other.Equals(Key);
    }
    #endregion

    #region IEquatable<IKeyed<ProcessStatus>> Members
    public bool Equals(IKeyed<ProcessStatus> other) {
        return other.Equals(Key);
    }
    #endregion
}

A lot of implementations of various interfaces and a few overrides here or there, but nothing too confusing. This code however, doesn't compile. I was surprised, theres no obvious syntax errors I saw.

Here's the error:

Error 1 The type 'JHeidt.Util.Core.ProcessStatus' cannot be used as type parameter 'KeyType' in the generic type or method 'JHeidt.Util.Core.IKeyed<KeyType>'. There is no boxing conversion from 'JHeidt.Util.Core.ProcessStatus' to 'System.IEquatable<JHeidt.Util.Core.ProcessStatus>'. C:\Documents and Settings\Jake\My Documents\Visual Studio 2008\Projects\JHeidt.Util\JHeidt.Util.Core\ProcessStatusNotifier.cs

Hrmm, a generics error, complaining that theres no way the compiler could find to allow the use of KeyType in the class because theres no conversion possible between the enum ProcessStatus and IEquatable<ProcessStatus>. What? Really? I shook my head, that can't be right.

It's right.

Enumerations of type XYZ DO NOT IMPLEMENT IEquatable<XYZ>. I have absolutely no idea why this is, but I have some guesses: due to the way enums are handled, I think that they aren't really first class objects, they are stepchildren of the '.net: everything is objects' world. Enums are all value types, and we know that you can inherit a specific type as the underlying types for an enum (using the :long syntax, etc). I guess that under the hood, enums are simply the value type, perhaps with a System.Type attached to them that says they belong to an enum. I know that we can cast an enum to its underlying value type, and back. And I know that you can create an invalid value by casting to the enum type, so I guess this is the underlying technical reason for the lack of IEquatable<XYZ>, Perhaps the runtime doenst know which IEquatable to use for the comparison (the system numeric types all implement this interface, so maybe it would leave an ambiguous path).

So, I created a (reference type) wrapper for the enum, but it leaves me feeling a bit dirty. Ideally, I would like to create an IEqualityComparer for my enum type, but that rules out using the interface WHERE predicate to specify, unless theres syntax that I'm not familiar with, because now KeyType needs to be either IComparable<KeyType> or have a class specified somewhere accessible that provides a IEqualityComparer for it. Are types that implement IEqualityComparer capable of being cast to IEquatable<KeyType>, I dont think so. There has to be an interfaced based way to do this, but the mental athletics involved already confused me.

posted @ Friday, April 25, 2008 10:26 PM | Feedback (0) |

Sunday, April 20, 2008

Detailing...

I detailed my car on Saturday. Being the nerd that I am, I read up on a few forums on the best process for waxing your car. Admittedly, I have only waxed a car twice before, both times it was my old Saturn SC2. I don't think I ever washed my Passat, and I only took it through a automatic car wash maybe four or five times, it just didn't make sense to try to keep it clean while I was living in Newark. It just seems to rain dust there.

I used Mother Gold car wash, that stuff smells great. I followed up by claying my car, this was Meguilar's claybar detailing kit, I clayed my mom's car first to get the hang of it, and then took out a small surface plastic mark on my car. And then prompty dropped the clay on the ground, which means it becomes garbage - you don't want to scrub the surface of your car with rocks. So, after that small failure I used NXT Tech Wax 2.0, a very web-enabled sounding enterprise car exterior waxing solution. It's a liquid wax, but it got a lot of amazing reviews, so I used it. I don't have an orbital buffer or anything though, so it was all elbow grease. I gotta say, it came out great, but you can take a look for yourself.

Click to embiggen.

Jake's G37s

posted @ Sunday, April 20, 2008 2:44 PM | Feedback (0) |

Tuesday, March 11, 2008

Meep Meep

Infiniti G37sAfter looking at suspension and engine repairs that totaled way more than the blue book value of my old passat, I got a new car. This time I felt like getting something with a bit more zip. I know I haven't posted much lately, but I've been having way too much fun riding around (read: sitting on Rt. 18 traffic).

 

It's an Infiniti G37s. It's very fun to drive, it's very comfortable, and it's got some kick.

On a completely unrelated note, I saw some requests for my VS color scheme in 2005 format. I do have that, but it also includes and uses Resharper settings. I'll post that version from my old work machine, and I think I have one sitting around without it.

posted @ Tuesday, March 11, 2008 10:02 PM | Feedback (0) |

Friday, December 28, 2007

Ho Ho Ho

Well, another year gone by, but it's been an interesting one for .net and GIS developers like myself. The Katmai spatial beta, VS 2k8, silverlight, 3.5, and the ASP.NET MVC framework (c'mon guys a better name please?) all came out this year. Each worthy of their own dedicated blogs, let alone posts, but I must say I am looking forward to development work on SQL 2008 the most (surprise). The spatial functionality alone is amazing, let alone the other sweet stuff the bolted on - the hierarchical data type is interesting indeed. My community work with .netTiers has slowed as I try to figure out how we can bring the new LINQ and 2K8 functionality to the plate. I'm still not exactly sure, and to be honest, development work inside the .netTiers is not very structured, to say the least. Right hand meet left hand, etc.

I really wish I could show some of the amazing stuff I've been doing with SQL server, it's really really awesome and interesting, but a lot of the stuff I've been working on can be directly used at work so of course that takes precedence. Stay tuned though, our spatial data work at Spatial Data Logic is quite cutting edge indeed.

posted @ Friday, December 28, 2007 11:02 PM | Feedback (0) |

Wednesday, December 19, 2007

Sure signs of the apocolypse

DN4 nuke

Today the IE team announced that a recent checkin to the codebase allows IE8 to pass the important Acid2 test. If any of you have just felt that deep down hatred of all things IE at some point in your web development travels (we all have), you probably know that rendering this test proves a TON about the positioning and image rule rendering code in the IE codebase - this is a HUGE step.

Also today, there was a release of a Duke Nukem screen cap, and a freaking trailer!

IE rendering web standards correctly?!
Duke nukem coming out!?

posted @ Wednesday, December 19, 2007 4:15 PM | Feedback (0) |

Thursday, December 13, 2007

Visual Studio Color Scheme

I have tweaked this color scheme for a while now, I'm quite a fan of the current setup. I just wish that Resharper would come out for 2008 so that I could have the advanced coloring options I had available in 2005. Requires VS 2K8. I use the Dina Font in my output windows, it's worth a download.

Visual Studio 2008 Color Scheme Thumbnail

Download Visual Studio 2008 Settings File (.vssettings)

posted @ Thursday, December 13, 2007 4:13 PM | Feedback (9) |

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) |

Thursday, November 29, 2007

Full Vista Wipe

Well after a particularly nasty run-in trying to install/un-install SQL Server 2008 on a PC that was then renamed and turned into a domain controller, I have wiped my PC and reset my local network server. I have everything backed up, of course, it was an intentional wipe after all. I am glad that I can cleanly install the applications on PC without any clutter, that always gives me that spring-time fresh feeling. I have not forgotten about the CSS Packer! Once I have my local IIS setup (it was a bear to configure for development last time), and talking with a SQL server I'll post something useful. Until then, I'll be installing more applications.

There seems to be a pattern to the applications I always reinstall. Because it's so trendy to post lists, here is my must-haves (in rough install order).

Firefox - my browser of choice.

Firefox Addons: Firebug, Download Statusbar, del.icio.us

WinRAR - I have used 7zip, and I prefer to use OSS, but I have grown to love the winrar over the years.

CCleaner - everyone should use this application. It should come pre-installed on windows. (Don't next,next,next your way into Yahoo toolbar if you don't want it.)

Combined Community Codec Pack - Gets everything to play right on media center, and in windows in general. A praiseworthy effort by the video community.

Quicktime Alternative - Quicktime has become a massive piece of bloat, installing all sorts of other applications along with it. No thanks. Sorry apple.

Programmers Notepad - my text editor of choice, I used to use EditPlus for years, but I like the scaled back design of pnotepad. Exactly what I wanted. Thanks Simon Steele!

XnView - I've used this for years now, I'm not really attached to it, anyone have a good recommendation for an open source image viewer without bloat? (media playback wtf?!)

Daemon Tools - Drive image / disc image mounter. Generally awesome. (Do you want me to burn these CTPs and RCs to plasticware?)

Hamachi - VPN software, I'm a new recruit to this, but it's installed on pretty much all of my pcs. I would MUCH rather use an OPEN vpn platform, so people can check for security problems, backdoors, etc. But Hamachi is a well respected and trusted application from a well respected and trusted company, and the price is right.

ImgBurn - Burns disc images, rips disc images. Tends to be the only application to use my optical drives.

SQL Server Current Flavor Edition / Express (sometimes) - The database I do most development on at work, thus I use it at home instead of MySql (which I also do use, but not as often).

Visual Studio Version Right Now - This IDE just keeps getting bigger, and bigger, but instead of turning crappier and crappier it just keeps bringing the hits.

Resharper - is there anyone that even runs VS without it these days? If so, do you enjoy getting paid by the hour?

Snippet Compiler - to run a quick and dirty .net function, or use code to solve a logic/math problem. If you haven't tried it, check it out, it's basically a super slim .net IDE made for running one-off code.

CodeSmith - God spoke upon his prophet, Eric Smith,  "Tell them to codegen what they can." And he let them. And it was AWESOME. This application is worth every cent. If you haven't used it, you should try it, if you have ever written an app to generate code (who hasn't?) at some point, check out this implementation of it. It's killer. I'm not sold on the VS integration really, to be honest, but as a codegen platform I have not seen one better.

And, Windows Live Writer, to make these posts. It's quite an amazing application indeed.

I'm not affiliated in any way, other than the use of, any of these applications, their owners, or anything - so I'm not trying to sucker anyone into installing stuff listed here. Likewise, if one of these applications makes your house blow up or causes your dog to violently ignite, please don't blame me.

posted @ Thursday, November 29, 2007 7:53 PM | Feedback (2) | Filed Under [ Non technical ]

Tuesday, November 20, 2007

SpriteGen - Implementation Part 1

Alright, well I've reached a point now in the implementation of the JHeidt.Utilities.Web.CssSpriteGen library where I feel comfortable not only sharing my implementation details, but hopefully some starter code to get down to the idea of the design behind it. If you haven't been following my posts on the subject, SpriteGen is an extensible library of which the goal is to take a series of images from a given input source and generate a packed raster representation of those images along with the requisite CSS rules and XHTML examples to showcase them, for your use however you please.

There currently exist a few services for creating CSS sprites, but the whole goal of CSS sprites is to allow for quicker loading of images/styles on the client side, by cutting down on request calls / upstream network bandwidth. So here is the first unequal size inputs packed image example and result, showing how I minimize the image output size by using bin packing techniques:

These images were taken, (without express written consent, but in the hopes of promoting them) from http://microformats.org/wiki/buttons. Please learn about microformats and help spread the word as well about helping make the web a contextual, and data rich environment.

Well  - Here are the source images.
Note the varying height and width:

515843744_57bd70fdf5_o 515843768_98956242a7_o 515868619_ed9cda470a_o 1296783076_1d6fe8a1f8_m emf_green hcal icon-hatom icon-hcalendar icon-hcard-add icon-hcard-download icon-hresume

icon-rel-tag icon-xfn license logo mfe_green microformat microformat_enabled microformat_hcalendar

 microformat_hcard microformats1 mwmf_green pdffile smf_green svgfile

tag-ltblue vote-against vote-for xfn-colleague xfn-colleague-met xfn-friend xfn-friend-met xfn-me xfn-sweetheart xfn-sweetheart-met


Source Image Zip: Source Images.zip

The total area for these combined input images is 89442 pixels. A perfect packing of these images (which is quite probably not possible for these inputs) would yield an image of that area.

Below we get the image that was created by SpriteGen. The ImageLoader for this case was the DirectoryImageLoader, with the default options. Image loaders provide a set of base image searching, preparation, and validation functions, and there are more options and specifics for the base and custom image loaders.

The DirectoryLoader has options for max input file size, max directory iteration file processor count, cutoff at combined total input area, max binary result size, file mask, and even more - the reason for these configurable settings was the expectation that people could use the spritegen online, perhaps forgetting to shrink an image, or upload an invalid zip file, or just downright abuse. It's important to note that I've created 3 ImageLoaders for SpriteGen so far, but the fully functional ones right now are the DirectoryLoader and the ZipFileLoader.

I can see creating a UrlScrapeLoader that could parse images from a remote web site and it's css to generate the packed images and CSS for that site as just a dead-lazy gimmegimme sprites hookup, but that's further down the road ;). Also, additions that I think would be useful would be the ability to generate output images grouped by input type, or to detect non-alpha & per-pixel alpha images and group them in with gif/JPEG raster groups as required, again to save bandwidth, so these will be looked at.

So - without further ado, here is the pack image result (output: PNG/full alpha - this can be adjusted or even broken down to separate outputs from a set of input images) This output doesn't showcase the SmartBackGround functions ability to determine repeated/repeatable background images, such as vertically aligned 1px wide, 2px+ high images as repeat-x backgrounds and vice versa for repeat-y via 1px high, 2px+ wide images. Using the smart bg function these qualifying images would optionally be generated in a separate image file, to allow repeatability and also to maintain minimum file size, however options like these are fully customizable depending on how you prefer your output images in case you wanted them included in the packed image. (More on this later)

 

jheidt.com_SpriteGen_8c9f929807672c4.out

Final image: 72.4K.

Final image area in pixels is 93120 (240 * 388)

*Please note that my blog post software doesn't seem to like the PNG alpha in these images, but I assure it's there - click the image to open it and see for yourself. Also of note here is the detection of per-pixel alpha in the source images and producing the correct image format out.


Here is the resultant image from a similar online sprite generator:

csg-47427cb8638c5


Final image size: 84.8K. Final image area: 482880 (240 x 2012) - also note there seems to be some unexpected behavior around a few alpha-blended buttons, but I'm sure this is being addressed, or is already addressed, at the time of this post, stuff like this is relatively minor.

So you can see how this packing can be beneficial - the whole idea here is to clamp down on extraneous client requests to the server, but also to reduce the overall bandwidth (and subsequent load times) for images from our sites. The packing saved 12.4k for the same set of input images.

Example CSS and XHTML gets generated as well, with some good comments and recommendations to those might be a bit confused about this code, or how to use it in their project. I'll discuss this aspect of the SpriteGen next.

posted @ Tuesday, November 20, 2007 1:39 AM | Feedback (0) | Filed Under [ SpriteGen ]

Powered by: