Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

GPaint

0.00/5 (No votes)
7 Jun 2004 1  
GPaint: is a program to create Google-like logos.

Introduction

GPaint is a program to create Google-like logos. It is a command line program which takes as input a font name, a font size, the text, a "color cycling scheme", and a file name. The font of the Google logo is Catull, but Catull is a commercial font, so chances are you don't have it on your computer. Don't worry though, Book Antiqua looks a lot like Catull and, don't forget, you can use any font you like. When GPaint is invoked like this:

C:\>gpaint "book antiqua" 80 "Google" "2159d6;e73c21;efba00;2159d6;31b639" logo

You will get this .bmp file as a result (converted to jpeg):

OK, I admit, it is not exactly like the Google logo, but it's nice, isn't it?

GPaint will change the color for each character in the string. For example, suppose the color cycling scheme is "ff0000,0000ff", then GPaint will paint the first character in red, the second in blue, the third again in red etc.

GPaint Internals

GPaint uses the following classes: FastBitmap, Layer, Layers, LayeredImage and GPaint.

FastBitmap is a class which contains a Bitmap. It is called FastBitmap because it provides methods to access the bits of the Bitmap member without using the very slow GetPixel() and SetPixel() methods of the Bitmap class. The code has to be compiled with the /unsafe option because the GetPixel() and SetPixel() methods of FastBitmap use pointers.

LayeredImage represents an image which consists of 1 or more layers. Programs like Photoshop and GIMP use a stack of layers to create attractive images. GPaint contains a small "Image Composition Engine" like the ones found in those programs - a very small one.

Layers represents the layer stack. It has methods to add and copy a layer.

Layer represents, well, a layer.

Let's see how GPaint uses these classes to generate a logo. Here's some code which you can find in the Main() method of the GPaint class:

...

// create image


LayeredImage image = new LayeredImage(totalwidth + 4, 
                tm.tmHeight + 4 + 4);

First, we create a new LayeredImage. Totalwidth is the width of the string and tm.tmHeight the height of the string in the given font. The width and height is increased by 4 because of the drop shadow. We add another 4 pixels to the height to make sure the drop shadow is completely visible, but this value is arbitrary. Now that we have an image, we can continue to add some layers.

Layer bg = image.Layers.Add();
bg.Clear(Color.Black);
bg.DrawText(0, 0, s, font, new SolidBrush(Color.White));

The layer bg contains the text in white on a black background. We will use this layer as a mask.

Layer copybg = image.Layers.Copy(bg);
copybg.Blur(4, 4);

copybg is a copy of the bg layer. We blur it 4 pixels horizontally and 4 vertically. This layer will be used as a bump map, and an inverted copy of this layer will serve as the drop shadow.

Layer white = image.Layers.Add();
white.Clear(Color.White);

The layer white is simply the background.

Layer shadow = image.Layers.Copy(copybg);
shadow.Invert();
shadow.Opacity = 0.5;
shadow.OffsetX += 4;
shadow.OffsetY += 4;

Layer shadow contains the drop shadow. We copy the bump map, invert its colors, set the opacity to 0.5 to make it less dark, and move it a bit.

Int32 offsetx = 0;
Int32 colorindex = 0;
Layer final = image.Layers.Add();
for (Int32 i = 0; i < s.Length; i++) {
    Color c = colors[colorindex];
    colorindex++;
    if (colorindex >= colors.Length)
        colorindex = 0;
    SolidBrush brush = new SolidBrush(c);
    final.FillRectangle(offsetx, 0, widths[i], tm.tmHeight, brush);
    offsetx += widths[i];
}

final is the layer we will bump map. colors is the color cycling scheme and widths contains the width of each character in the string. A rectangle is painted "above" each character in the right color.

final.BumpMap(copybg, 135, 45, 3, false);

Now that we have a "flag-like" bitmap, we can bump map it with azimuth 135, elevation 45 and depth 3.

// very important -- Clone() bitmap, otherwise Lock()

// will be called twice!!

final.Mask = (FastBitmap)bg.Bitmap.Clone();

As said in the beginning, bg will be used as a mask. As a result, only the bump mapped text will be visible on this layer and the white background and drop shadow will show through.

FastBitmap result = image.Flatten();
result.Save(args[4] + ".bmp", ImageFormat.Bmp);

And finally, ladies and gentlemen, we flatten the image and write it to disk.

Some Thoughts

  • Maybe a better name would be GString?
  • I should organize the code a bit better. Putting filters in the layer class is not a good idea, but it's not my intention to write a complete image manipulation library.
  • Because I DllImport() GetCharWidth() to get the width of a character, I don't think GPaint runs on Mono.
  • If someone can try this program with font Catull, please tell me where I can see a picture.

Exercise

Write a program which adds drop shadows to pictures automatically.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here