Ant Generated Images, Revisited

So I recently found myself designing an interface for the site where you can get design pattern gear and found myself needing a gradient image for the design I had in mind. So I popped open Macromedia Fireworks and drew myself a gradient image with the right colors then popped it into the page only to realize that I actually wanted the image a little bit darker at one end and a bit lighter at the other end. I did this three or four times before I said, “there has got to be an easier way.”

There is. In fact, I have a post about it from only a few weeks ago.

The image I needed was pretty simple – it was a gradient from light to dark that was 150 pixels high, followed by a solid colored dark block 90 pixels high, and finished by a dark to light gradient image 350 pixels high. Since this will be repeated via CSS I only needed it to be one pixel wide.

Using the schema associated with my Ant image generator, I wrote this:

 <?xml version="1.0" encoding="ISO-8859-1"?>

<imageBank xmlns="http://mcdonaldland.info"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://mcdonaldland.info/files/imageGenerator
           http://mcdonaldland.info/files/imageGenerator/images.xsd">

    <image name="bg" path="/images" format="png">
        <conjoinedImage position="top">
            <gradientImage width="1"
                       height="150"
                       color1="D9D9FF"
                       color2="000066"
                       gradientStartX="0"
                       gradientStartY="0"
                       gradientEndX="0"
                       gradientEndY="150"/>

            <conjoinedImage position="top">

                <plainImage width="1"
                            height="90"
                            color1="000066"/>

                <gradientImage width="1"
                           height="350"
                           color1="000066"
                           color2="D9D9FF"
                           gradientStartX="0"
                           gradientStartY="0"
                           gradientEndX="0"
                           gradientEndY="350"/>

            </conjoinedImage>
        </conjoinedImage>
    </image>
</imageBank>

Despite the verbose look of it, the structure is actually very simple. Since I really needed three images, the top gradient, the middle solid section, then the bottom gradient, I had to use the conjoinedImage type. The position attribute of the conjoined image will determine where the first portion of the content images is in relation to the second. In this case I defined gradientImage as the first portion and another conjoinedImage as the second. Since I defined the position as “top”, the gradientImage will appear directly on top of the conjoined image. I then followed this same principle for the second conjoinedImage to get a solid section on top of another gradient.

The huge benefit of this is that all I have to do to change the entire image is type a couple of numbers! This means that if I decide I want my page background to culminate in #E0E0E0 instead of #CCCCFF then I simply need to change the values in the correct portion of the images.xml file, run “ant”, and copy the file to the appropriate directory.

Here is the page that I eventually created (although I decided not to go with this design). The background gradient is the one defined in the XML above. The smoke/lightening banner I created with Gimp after viewing this tutorial. I changed the colors roughly 20-30 times through the design process and each time I found it extremely simple to get a new set of images for my background, thanks to the Ant based image generator.

The Viola Factor

The voila factor is the embodiment of well written software. When the user sits down to use the application, be it command line, web, or GUI, it should just work. Voila.

For some reason so many applications fail to do this for a number of reasons. I have my theories of why this is, based upon personal experiences.

Here are a few:

1. Application designs are developer-centric.
The developer personality is usually one that likes solving problems. Because of this most developers love getting their hands on a juicy feature that they can “solve”. What sets the experienced developers apart from the less experienced is the amount of resolve that goes into ensuring that the design is what is best for the client instead of what is best for the developer. For example, I wrote an administration console for a client once that I was extremely proud of. I designed the system in such a way that I could add a new module to it without having to update but a few lines of code. This was back in the day before Ruby on Rails and Grails and it basically gave CRUD functionality to the administrator. They hated it. While the design was great from my standpoint, as it made updates extremely simple, it failed to meet the needs of the end user because they couldn’t relate to the system or figure out how to use it well.

2. Application designs are designer-centric.
We’ve all been to sites that are a marvel to look at but are near impossible to get anything done in. This item falls into the same category as #1, only with the designer at the core. Design applications for what users need, not for what designers want.

3. Someone forgot the KISS principle.
KISS stands for Keep It Simple Stupid or, as I like it, Keep It Stupid Simple. Developers are a creative bunch at heart and like to add cool extras as they are in the code. Many times these extras won’t even become apparent until an engineer has the code open and is digging through. While these bells and whistles may be nice one has to wonder if they actually adding to the overall user experience. In many cases less is truly more. If a good user experience can be achieved without the addition, perhaps it is best left out.

4. Time was not allocated well for the project.
This is the kiss of death for any project. You can’t decrease the time projects will take by throwing more people or more technology at it. While there are isolated cases where this will work, the body of evidence suggests that adding manpower will usually increase the time it takes to complete projects. When time is short developers are more likely to choose the fastest way to complete their work which, because of #1, makes the design developer-centric and rarely bodes well for the end user.

5. Things change from release to release without notifying the user.
This should be obvious. If CTRL+K serves one function in one release it should either serve the same function in the next release or the application should notify the user that things have changed. Many applications seem to get this right, however many don’t.

Ant Based Image Generator

Background:
This code works and works well. That said, it is not the prettiest bunch of code I have ever written. It just kind of came together so things could be done a bit more elegantly than they currently were and was never a pre-designed set of code. However, I go back to my opening statement: it works.

Overview:
I used to have a modular based build system where I had many components that were available for any given client. So if a client came and said that they wanted to allow users to log in, application management, and a forum then I would include those three modules into a properties file for them that would contain all details specific to the client. I would then type a few Ant commands and, Voila!, the site was ready. The system worked great until I started needing to change the look and feel of each module outside of just the general color scheme. Sometimes this meant custom text while others this mean gradients instead of plain colors. So, wanting to stick with my simple to use Ant based build system, I decided to create an imaging system that would allow me to change gradients and other stuff on the fly without affecting the underlying project.

So what I wound up with was an XML based system where you list details about how the system should create the images for a given module. So in order to create a new image I would have an images.xml file in the module directory with entries like this in it:

    <image name="titlebartop" path="/images" format="png">
        <gradientImage width="650"
                       height="25"
                       color1="5EFF72"
                       color2="6681FE"
                       gradientStartX="0"
                       gradientStartY="0"
                       gradientEndX="650"
                       gradientEndY="0"/>
    </image>

There is quite a bit of backing code that knows how to draw various types of images – solid color, gradients, text, shapes, or combinations of the previous – as well as how these things should fit together, should you indicate you want an image with combinations of these features. I will let you look into the details yourself but here is one example method for creating the actual gradient image using the Java 2D and AWT packages:

    private BufferedImage drawGradient(int width,
                                       int height,
                                       int gradientStartX,
                                       int gradientStartY,
                                       int gradientEndX,
                                       int gradientEndY,
                                       Color color1,
                                       Color color2) throws Exception {

        BufferedImage bi = new BufferedImage(width,
                                             height,
                                             BufferedImage.TYPE_INT_RGB);

        GradientPaint gp = new GradientPaint((float) gradientStartX,
                                             (float) gradientStartY,
                                             color1,
                                             (float) gradientEndX,
                                             (float) gradientEndY,
                                             color2);

        Graphics2D g = (Graphics2D) bi.getGraphics();
        g.setPaint(gp);

        g.fillRect(0, 0, width, height);

        return bi;
    }

I am out of the contracting game (for now at least) so I don’t really use this code anymore as I don’t have a huge need for large sets of like images. I just ran through and created a quick test page (in the images/test) directory with these images and everything but schema validation still works though.

Example:
Here is an example of it in action. This image is ugly, no doubt, but it shows the use of gradients and their alignment options, solid color pictures, basic shapes, and text all compiled into a single image. This is one of the actual images generated by the Ant task and is one of the ones displayed in the test.html file. Note that even the text has a gradient on it.

Get it:
Grab the zip file with the source in it here. Note that ALL images found in the test.html file are generated – none are hand made.

Usage:
Since this is an Ant based system you will need to have Ant on your system to compile the tasks or to run the Ant task.

1. Unzip the package to its destination on your computer.

2. Navigate to the directory in a command shell and type “ant”.

3. Open the ./images directory and you should see image files. You can open the ./images/test/test.html file to see these fancy-schmancy images in action. I just chose some random colors for illustration so it is kind of ugly.

4. Play with the values in the images.xml file then repeat from step 2.

5. If you are going to use this for anything production you’ll want to take a look at the XSD validation – it is currently commented out as it is not working right. It used to work but somewhere over time got broken and I didn’t feel like fixing it for this example. If you are interested in this contact me and I’ll be glad to help.

As always, this code is free to use, distribute, or modify so long as it is not used for financial gain without my consent. Enjoy!