<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>SpriteGen</title>
        <link>http://www.jheidt.com/category/4.aspx</link>
        <description>SpriteGen</description>
        <language>en-US</language>
        <copyright>Admin</copyright>
        <managingEditor>admin@jheidt.com</managingEditor>
        <generator>Subtext Version 1.9.5.177</generator>
        <item>
            <title>SpriteGen - Implementation Part 1</title>
            <link>http://jheidt.com/archive/2007/11/20/spritegen---implementation-part-1.aspx</link>
            <description>&lt;p&gt;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 &lt;a href="http://fatagnus.com/how-to-create-css-sprites/" target="_blank"&gt;packed raster representation of those images along with the requisite CSS rules&lt;/a&gt; and XHTML examples to showcase them, for your use however you please.&lt;/p&gt;  &lt;p&gt;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 &lt;a href="http://en.wikipedia.org/wiki/Bin_packing" target="_blank"&gt;bin packing&lt;/a&gt; techniques:&lt;/p&gt;  &lt;p&gt;These images were taken, (without express written consent, but in the hopes of promoting them) from &lt;a href="http://microformats.org/wiki/buttons" target="_blank"&gt;http://microformats.org/wiki/buttons&lt;/a&gt;. Please learn about &lt;a href="http://en.wikipedia.org/wiki/Microformats" target="_blank"&gt;microformats&lt;/a&gt; and help spread the word as well about helping make the web a contextual, and data rich environment.&lt;/p&gt;  &lt;p&gt;Well  - Here are the source images.    &lt;br /&gt;Note the varying height and width:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/515843744_57bd70fdf5_o.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="515843744_57bd70fdf5_o" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/515843744_57bd70fdf5_o_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/515843768_98956242a7_o.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="515843768_98956242a7_o" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/515843768_98956242a7_o_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/515868619_ed9cda470a_o.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="515868619_ed9cda470a_o" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/515868619_ed9cda470a_o_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/1296783076_1d6fe8a1f8_m.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="182" alt="1296783076_1d6fe8a1f8_m" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/1296783076_1d6fe8a1f8_m_thumb.jpg" width="240" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/emf_green.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="31" alt="emf_green" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/emf_green_thumb.png" width="88" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/hcal.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="15" alt="hcal" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/hcal_thumb.png" width="80" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhatom.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="icon-hatom" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhatom_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhcalendar.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="icon-hcalendar" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhcalendar_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhcardadd.png"&gt;&lt;img height="18" alt="icon-hcard-add" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhcardadd_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhcarddownload.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="icon-hcard-download" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhcarddownload_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhresume.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="icon-hresume" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconhresume_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconreltag.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="icon-rel-tag" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconreltag_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconxfn.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="icon-xfn" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/iconxfn_thumb.png" width="29" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/license.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="15" alt="license" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/license_thumb.png" width="80" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/logo.gif"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="36" alt="logo" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/logo_thumb.gif" width="144" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/mfe_green.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="31" alt="mfe_green" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/mfe_green_thumb.png" width="88" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformat.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="15" alt="microformat" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformat_thumb.png" width="80" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformat_enabled.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="15" alt="microformat_enabled" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformat_enabled_thumb.png" width="80" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformat_hcalendar.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="15" alt="microformat_hcalendar" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformat_hcalendar_thumb.png" width="80" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformat_hcard.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="15" alt="microformat_hcard" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformat_hcard_thumb.png" width="80" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformats1.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="40" alt="microformats1" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/microformats1_thumb.png" width="150" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/mwmf_green.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="31" alt="mwmf_green" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/mwmf_green_thumb.png" width="88" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/pdffile.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="64" alt="pdffile" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/pdffile_thumb.png" width="64" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/smf_green.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="31" alt="smf_green" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/smf_green_thumb.png" width="88" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/svgfile.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="64" alt="svgfile" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/svgfile_thumb.png" width="64" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/tagltblue.gif"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="tag-ltblue" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/tagltblue_thumb.gif" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/voteagainst.gif"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="vote-against" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/voteagainst_thumb.gif" width="21" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/votefor.gif"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="18" alt="vote-for" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/votefor_thumb.gif" width="21" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfncolleague.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="14" alt="xfn-colleague" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfncolleague_thumb.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfncolleaguemet.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="14" alt="xfn-colleague-met" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfncolleaguemet_thumb.png" width="23" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnfriend.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="14" alt="xfn-friend" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnfriend_thumb.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnfriendmet.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="14" alt="xfn-friend-met" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnfriendmet_thumb.png" width="23" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnme.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="14" alt="xfn-me" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnme_thumb.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnsweetheart.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="14" alt="xfn-sweetheart" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnsweetheart_thumb.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnsweetheartmet.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="14" alt="xfn-sweetheart-met" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/xfnsweetheartmet_thumb.png" width="23" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;hr style="clear: both" /&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Source Image Zip: &lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/MicroformatIcons.zip" target="_blank"&gt;Source Images.zip&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;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 &amp;amp; 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.&lt;/p&gt;  &lt;p&gt;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)&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/jheidt.com_SpriteGen_8c9f929807672c4.out.png"&gt;&lt;img id="id" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="388" alt="jheidt.com_SpriteGen_8c9f929807672c4.out" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/jheidt.com_SpriteGen_8c9f929807672c4.out_thumb.png" width="240" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Final image: 72.4K. &lt;/p&gt;  &lt;p&gt;Final image area in pixels is 93120 (240 * 388) &lt;/p&gt;  &lt;p&gt;*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. &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;hr style="clear: both" /&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Here is the resultant image from a similar online sprite generator:&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/csg47427cb8638c5_3.png"&gt;&lt;img id="id" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="2012" alt="csg-47427cb8638c5" src="http://www.jheidt.com/Images/BlogPosts/SpriteGenImplementationPart1_160C/csg47427cb8638c5_thumb_3.png" width="240" align="left" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;hr style="clear: both" /&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;&lt;img src="http://jheidt.com/aggbug/6.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Admin</dc:creator>
            <guid>http://jheidt.com/archive/2007/11/20/spritegen---implementation-part-1.aspx</guid>
            <pubDate>Tue, 20 Nov 2007 06:39:49 GMT</pubDate>
            <wfw:comment>http://jheidt.com/comments/6.aspx</wfw:comment>
            <comments>http://jheidt.com/archive/2007/11/20/spritegen---implementation-part-1.aspx#feedback</comments>
            <wfw:commentRss>http://jheidt.com/comments/commentRss/6.aspx</wfw:commentRss>
            <trackback:ping>http://jheidt.com/services/trackbacks/6.aspx</trackback:ping>
        </item>
        <item>
            <title>SpriteGen Update</title>
            <link>http://jheidt.com/archive/2007/11/13/spritegen-update.aspx</link>
            <description>&lt;p&gt;Alright, well I've implemented everything necessary, including all of the configuration code, for the base SpriteGen to work. So, as soon as I get some ghetto pages together to allow you to upload a zip and process it, I'll let you know via an update here. However, the way the SpriteGen queues work items and notifies you that 'your sprites are ready' will likely be changed, due to the fact that I eventually expect some decent traffic coming through and using it. The packing algorithm is pretty slim and easy, but who knows how hard it would make my web server work with 20 concurrent requests. &lt;/p&gt;  &lt;p&gt;Stay tuned for the URL to the SpriteGen.&lt;/p&gt;&lt;img src="http://jheidt.com/aggbug/5.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Admin</dc:creator>
            <guid>http://jheidt.com/archive/2007/11/13/spritegen-update.aspx</guid>
            <pubDate>Tue, 13 Nov 2007 05:13:47 GMT</pubDate>
            <wfw:comment>http://jheidt.com/comments/5.aspx</wfw:comment>
            <comments>http://jheidt.com/archive/2007/11/13/spritegen-update.aspx#feedback</comments>
            <wfw:commentRss>http://jheidt.com/comments/commentRss/5.aspx</wfw:commentRss>
            <trackback:ping>http://jheidt.com/services/trackbacks/5.aspx</trackback:ping>
        </item>
        <item>
            <title>Creating CSS Sprites, An Intro</title>
            <link>http://jheidt.com/archive/2007/11/04/creating-css-sprites-an-intro.aspx</link>
            <description>&lt;p&gt;If you are not familiar with CSS sprites, I can think of no better place for an introduction than &lt;a href="http://www.alistapart.com/articles/sprites"&gt;this article&lt;/a&gt; on A List Apart. In short, you place many images into one image file, and then use that image as a background image and modify its position using background-position attributes. The only problem with the process is that its quite laborious, and really is robot work. While I was working on some html design a few weeks ago I became frustrated at this process, so I decided to figure out a way to automate it.&lt;/p&gt;  &lt;p&gt;Now, admittedly, there already exist a few CSS sprite generators on the Internet, but in my opinion they left something to be desired. The big reason to create CSS sprites is to cut down on relatively sizable http requests (in comparison to the small images they may be requesting), in favor of one image that will be cached on the client side. A sweet side effect of this is that rollover images states don't require any JavaScript client-side code to preload any images, the browser takes care of it in the original image download. The problem is, in my experience, the existing generators don't actually save any bandwidth. By inefficiently placing the images into the output image they actually end up adding a bit too much to the final image output size. While doing research as to how to minimize the output of such an image placement algorithm I ran headfirst into a fun computational challenge. The problem is a &lt;a href="http://en.wikipedia.org/wiki/NP-hard"&gt;NP-Hard&lt;/a&gt; computation that is known as the &lt;a href="http://en.wikipedia.org/wiki/Bin_packing_problem"&gt;bin packing problem.&lt;/a&gt; Fortunately, placing images that I have a list of is known as an 'offline' bin packing problem, meaning that I have the full set of inputs and I can generate a relatively decent output image from it. &lt;/p&gt;  &lt;p&gt;When I was researching how to place the images, I read a great &lt;a href="http://www.math.niu.edu/~rusin/known-math/99/packsums"&gt;series of e-mails&lt;/a&gt; from a mailing list in which Clive Tooth explains an intuitive algorithm:&lt;/p&gt;  &lt;blockquote&gt;The new method works by sub-dividing the remaining part of the original rectangle into sub-rectangles and then, when a new square is to be inserted, choosing one of the subrectangles which will completely hold the square and then positioning the square at the top left hand corner of the rectangle. The remaining L-shaped part of the rectangle is then partitioned into two rectangles. Occasionally one of the two new rectangles may have a zero height or zero width, but this does not matter. Thus at each stage one rectangle is used and replaced by two smaller rectangles. Thus, just before inserting piece n, the remaining space will have been split into n rectangles. So, we would need to prove that at that stage at least one of the rectangles had a short side of least 1/n. &lt;/blockquote&gt;  &lt;p&gt;In short, as long as you have the correct size to output to, you can place a rectangle inside that output with decent efficiency. In further research I found that the output image was proven to never be more than 70% inefficient, but in practice in my tests it's actually been much closer to 20% or so. I also created my own algorithm for generating an estimate output rectangle size for containing a list of images, that seems to correctly guess the output size.&lt;/p&gt;  &lt;p&gt;Within a few days I hope to show some code, but for now here is a little taste of the output of 16x16 images from the &lt;a href="http://www.famfamfam.com/lab/icons/silk/"&gt;awesome silk icon set&lt;/a&gt;:&lt;/p&gt; &lt;img id="id" src="http://www.jheidt.com/Images/BlogPosts/CreatingCSSSpritesAnIntro_1341B/output633294828521731575_3.png" /&gt; &lt;br /&gt; &lt;p&gt;Note that this doesn't show any of the more intricacies of the algorithm, but it does show where I'm going with it. &lt;/p&gt;&lt;img src="http://jheidt.com/aggbug/3.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Admin</dc:creator>
            <guid>http://jheidt.com/archive/2007/11/04/creating-css-sprites-an-intro.aspx</guid>
            <pubDate>Mon, 05 Nov 2007 02:55:24 GMT</pubDate>
            <wfw:comment>http://jheidt.com/comments/3.aspx</wfw:comment>
            <comments>http://jheidt.com/archive/2007/11/04/creating-css-sprites-an-intro.aspx#feedback</comments>
            <wfw:commentRss>http://jheidt.com/comments/commentRss/3.aspx</wfw:commentRss>
            <trackback:ping>http://jheidt.com/services/trackbacks/3.aspx</trackback:ping>
        </item>
    </channel>
</rss>