Lua-GD Logo

Lua-GD 2.0.33r2

Contents

Introduction

"gd" is a C graphics library created by Thomas Boutell that allows your code to quickly draw complete images with lines, polygons, arcs, text, multiple colors, cut and paste from other images, flood fills, read in or write out images in the PNG, JPEG or GIF format. This is particularly useful in World Wide Web applications, where PNG and JPEG are two of the formats accepted for inline images by most browsers. gd does not provide for every possible desirable graphics operation. It is not necessary or desirable for gd to become a kitchen-sink graphics package, but it does include most frequently requested features, including both truecolor and palette images, resampling (smooth resizing of truecolor images) and so forth. You can get more information about gd from it's homepage.

Lua-GD is a "binding": a library that exports gd functions to the Lua Programming Language, allowing you to use gd from Lua. The API was NOT literally exported, but changed in a way that make it familiar to Lua users.

Lua-GD is a programming library, not a paint program. If you are looking for that or are not familiar to the Lua Programming Language, you are in the wrong place.

This document, which was heavly based on gd manual, describes the API and provides the information needed to use the library. Some experience with Lua is required.

A NOTE ON VERSION NUMBERS: Lua-GD version numbers is in the format "X.Y.ZrW", where X.Y.Z indicates the gd version and W the binding version. So, the 2.0.33r1 version is the first binding version for gd 2.0.33 and 2.0.33r2 has some improvements/bug fixes/etc. but uses the same gd version.

Licensing information

Lua-GD and gd have diferent licenses. In order to use Lua-GD in your application, you need to accept both them.

Lua-GD License

Lua-GD is copyrighted free software, distributed under the MIT license (the same used by Lua 5.1) and it can be used at no cost for both academic and commercial purpouses. Or, more precisely:

Lua-GD (c) 2004-2006 Alexandre Erwin Ittner

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

If you use this package in a product, an acknowledgment in the product
documentation would be greatly appreciated (but it is not required).

gd License

Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 by Cold Spring Harbor Laboratory. Funded under Grant P41-RR02188 by the National Institutes of Health.

Portions copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 by Boutell.Com, Inc.

Portions relating to GD2 format copyright 1999, 2000, 2001, 2002, 2003, 2004 Philip Warner.

Portions relating to PNG copyright 1999, 2000, 2001, 2002, 2003, 2004 Greg Roelofs.

Portions relating to gdttf.c copyright 1999, 2000, 2001, 2002, 2003, 2004 John Ellson (ellson@graphviz.org).

Portions relating to gdft.c copyright 2001, 2002, 2003, 2004 John Ellson (ellson@graphviz.org).

Portions relating to JPEG and to color quantization copyright 2000, 2001, 2002, 2003, 2004, Doug Becker and copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Thomas G. Lane. This software is based in part on the work of the Independent JPEG Group. See the file README-JPEG.TXT for more information.

Portions relating to GIF compression copyright 1989 by Jef Poskanzer and David Rowley, with modifications for thread safety by Thomas Boutell.

Portions relating to GIF decompression copyright 1990, 1991, 1993 by David Koblas, with modifications for thread safety by Thomas Boutell.

Portions relating to WBMP copyright 2000, 2001, 2002, 2003, 2004 Maurice Szmurlo and Johan Van den Brande.

Portions relating to GIF animations copyright 2004 Jaakko Hyvätti (jaakko.hyvatti@iki.fi)

Permission has been granted to copy, distribute and modify gd in any context without fee, including a commercial application, provided that this notice is present in user-accessible supporting documentation.

This does not affect your ownership of the derived work itself, and the intent is to assure proper credit for the authors of gd, not to interfere with your productive use of gd. If you have questions, ask. "Derived works" includes all programs that utilize the library. Credit must be given in user-accessible documentation.

This software is provided "AS IS." The copyright holders disclaim all warranties, either express or implied, including but not limited to implied warranties of merchantability and fitness for a particular purpose, with respect to this code and accompanying documentation.

Although their code does not appear in the current release, the authors also wish to thank Hutchison Avenue Software Corporation for their prior contributions.

Download and installation

Lua-GD source code comes in a tar.gz package that can be downloaded from the Lua-GD project page on LuaForge or from its mirror on Sourceforge. There are also some pre-compiled binary packages available for Linux and some other Unix systems.

After downloading, you need to compile the library. This process requires GNU Make, gd and its dependencies (libpng, libjpeg, FreeType2, fontconfig, etc.) installed on your system. Some components that may be disabled on your gd installation will be disabled in Lua-GD too. To compile on Unix, just unpack the distribution package, enter the directory and type make in your favourite shell. If the compilation was successful, you will see something like:

gcc -o gd.so `gdlib-config --features |sed -e "s/GD_/-DGD_/g"`
`gdlib-config --cflags` `pkg-config lua5.1 --cflags` -O3 -Wall -shared
`gdlib-config --ldflags` `gdlib-config --libs` `pkg-config lua5.1 --libs`
-lgd luagd.c
lua test_features.lua
Lua-GD version: lua-gd 2.0.33r2
Lua-GD features:
    PNG support ..................... Enabled
    GIF support ..................... Enabled
    JPEG support .................... Enabled
    XPM/XBM support ................. Enabled
    FreeType support ................ Enabled
    Fontconfig support .............. Enabled

To install the library with Lua 5.1 and above just type make install, as root.

WARNING: This will work only in systems with pkg-config (which includes the major Linux distributions). In other systems, you will need to edit the Makefile and manually install the library, by copying the 'gd.so' file to your Lua binary modules directory.

Compiling Lua-GD on Windows systems is almost, but not quite, entirely unlike compiling it on Unix. You will need to edit the Makefile by yourself.

A NOTE TO DEBIAN/UBUNTU USERS: To enable the Fontconfig and XPM support, you will need the libgd2-xpm and libgd2-xpm-dev packages. The libgd2-noxpm does not have Fontconfig support.

Library loading and initialization

Lua-GD uses the Lua 5.1 package system that allows you to simply do a

require "gd"

call to load up the library.

Lua-GD API

The Lua-GD API is not identical to the gd C API: it was changed in a way that make it more familiar to Lua users and use the extra power provided by Lua, at cost of some learning for those that already use gd.

All the functions and constants are stored on a single global module called gd. Images are objects and they can use the common colon notation for its methods, but you can also use a C-style syntax. So, the following two lines are equivalent:

local gray1 = im:colorResolve(128, 128, 128)        -- Using the colon notation
local gray2 = gd.colorResolve(im, 128, 128, 128)    -- Using a C-style notation

Constants, functions and methods are described bellow.

Constants

gd.VERSION

A string with the version and some information about the library.

gd.MAX_COLORS

The constant 256. This is the maximum number of colors in a palette-based PNG file according to the PNG standard, and is also the maximum number of colors in a palette-based gd image. This of course does not apply to truecolor images.

gd.GD2_FMT_RAW
gd.GD2_FMT_COMPRESSED

Used when saving images to GD2 files with gd2 and gd2Str to indicate the image file format. This format is not intended for general purpose use and should never be used to distribute images. It is a file format allowing pseudo-random access to large image files. Its purpose is solely to allow very fast loading of parts of images. You should use GD2_FMT_RAW for faster loading (and bigger files) or GD2_FMT_COMPRESSED for smaller files (and slower loading).

gd.ARC
gd.CHORD
gd.PIE
gd.NO_FILL
gd.EDGED

These constants are used with the method filledArc and can be added together. gd.ARC, gd.CHORD, gd.PIE (synonym for gd.CHORD), gd.NO_FILL and gd.EDGED are mutually exclusive; gd.CHORD just connects the starting and ending angles with a straight line, while gd.ARC produces a rounded edge. gd.PIE is a synonym for gd.ARC. gd.NO_FILL indicates that the arc or chord should be outlined, not filled. gd.EDGED, used together with gd.NO_FILL, indicates that the beginning and ending angles should be connected to the center; this is a good way to outline (rather than fill) a 'pie slice'. See gd.filledArc for details.

gd.ANTI_ALIASED

Used in place of a color when invoking a line-drawing method such as gd.line or gd.rectangle. When gd.ANTI_ALIASED is used as the color, the foreground color set with gd.setAntiAliased is used, with antialiasing mechanisms to minimize any "jagged" appearance. For more information, see gd.setAntiAliased.

gd.BRUSHED

Used in place of a color when invoking a line-drawing method such as gd.line or gd.rectangle. When gd.BRUSHED is used as the color, the brush image set with gd.setBrush is drawn in place of each pixel of the line (the brush is usually larger than one pixel, creating the effect of a wide paintbrush). See also gd.STYLED_BRUSHED for a way to draw broken lines with a series of distinct copies of an image.

gd.STYLED

Used in place of a color when invoking a line-drawing method such as gd.line or gd.rectangle. When gd.STYLED is used as the color, the colors of the pixels are drawn successively from the style that has been set with gd.setStyle. If the color of a pixel is equal to gd.TRANSPARENT, that pixel is not altered. (This mechanism is completely unrelated to the "transparent color" of the image itself; see gd.colorTransparent for that mechanism).

gd.STYLED_BRUSHED

Used in place of a color when invoking a line-drawing method such as gd.line or gd.rectangle. When gd.STYLED_BRUSHED is used as the color, the brush image set with gd.setBrush is drawn at each pixel of the line, providing that the style set with gd.setStyle contains a nonzero value (OR gd.TRANSPARENT, which does not equal zero but is supported for consistency) for the current pixel. (Pixels are drawn successively from the style as the line is drawn, returning to the beginning when the available pixels in the style are exhausted). Note that this differs from the behavior of gd.STYLED, in which the values in the style are used as actual pixel colors, except for gd.TRANSPARENT.

gd.TILED

Used in place of a normal color in gd.filledRectangle, gd.filledPolygon, gd.fill, and gd.fillToBorder. gd.TILED selects a pixel from the tile image set with gd.setTile in such a way as to ensure that the filled area will be tiled with copies of the tile image. See the discussions of gd.fill and gd.fillToBorder for special restrictions regarding those methods.

gd.TRANSPARENT

Used in place of a normal color in a style to be set with gd.setStyle. gd.TRANSPARENT is not the transparent color index of the image; for that functionality please see gd.colorTransparent.

gd.FONT_TINY
gd.FONT_SMALL
gd.FONT_MEDIUM
gd.FONT_LARGE
gd.FONT_GIANT

These are the standard gd fonts used by gd.string and gd.stringUp. Sizes and styles are shown bellow:
Standard gd fonts
If you need another fonts, you should use TrueType fonts with gd.stringFT.

gd.FTEX_Unicode
gd.FTEX_Shift_JIS
gd.FTEX_Big5

These are the character maps used by gd.stringFTEx. Explicit specification of the desired character mapping is useful when a font offers more than one of Unicode, Shift_JIS, and Big5.

Image creation and destruction

gd.create(x, sy)
gd.createPalette(x, y)

These functions are used to create palette-based images, with no more than 256 colors. Invoke gd.create with the x and y dimensions of the desired image to return the new image or nil on error. gd.createPalette is a synomym for gd.create.

Example:

-- creates a 20x20px palette-based image
local im = gd.create(20, 20)

You don't need to destroy an image by yourself. Lua has a garbage collector that detects when an piece of information becomes useless and "automagically" removes it from memory.

gd.createTrueColor(x, y)

Used to create truecolor images, with an essentially unlimited number of colors. Invoke gd.createTrueColor with the x and y dimensions of the desired image to return the new image or nil on error. Truecolor images are always filled with black at creation time. There is no concept of a "background" color index.

Example:

-- creates a 20x20px true color image
local im = gd.createTrueColor(20, 20)

You don't need to destroy an image by yourself. Lua has a garbage collector that detects when an piece of information becomes useless and "automagically" deletes it from memory.

gdImage:createPaletteFromTrueColor(dither, colorsWanted)

This method creates a new palette-based image from a truecolor image using a high-quality two-pass quantization routine. If the dither flag is set to true, the image will be dithered to approximate colors better, at the expense of some obvious "speckling". colorsWanted, an integer value, can be anything up to 256. If the original source image includes photographic information or anything that came out of a JPEG, 256 is strongly recommended. 100% transparency of a single transparent color in the original truecolor image will be preserved. There is no other support for preservation of alpha channel or transparency in the destination image.

For best results, don't use this method -- write real truecolor PNGs and JPEGs. The disk space gain of conversion to palette is not great (for small images it can be negative) and the quality loss is ugly.

Image input functions

gd.createFromJpeg(filename)

gd.createFromJpeg is called to load truecolor images from JPEG format files. Invoke gd.createFromJpeg with a string pointing to an existing file containing the desired image to return a new truecolor image or nil if unable to load the image (most often because the file is corrupt or does not contain a JPEG image). You can determine the size of the image with gd.sizeXY. The returned image is always a truecolor image.

gd.createFromPng(filename)

gd.createFromPng is called to load images from PNG format files. Invoke gd.createFromPng with a string pointing to an existing file containing the desired image to return a new image or nil if unable to load the image (most often because the file is corrupt or does not contain a PNG image). You can determine the size of the image with gd.sizeXY.

If the PNG image being loaded is a truecolor image, the resulting value will refer to a truecolor image. If the PNG image being loaded is a palette or grayscale image, the resulting data will refer to a palette image. gd retains only 8 bits of resolution for each of the red, green and blue channels, and only 7 bits of resolution for the alpha channel. The former restriction affects only a handful of very rare 48-bit color and 16-bit grayscale PNG images. The second restriction affects all semitransparent PNG images, but the difference is essentially invisible to the eye. 7 bits of alpha channel resolution is, in practice, quite a lot.

Example:

-- copies the content of picture.png to a new image
local im = gd.createFromPng("picture.png")

gd.createFromGif(filename)

gd.createFromGif is called to load images from GIF format files. Invoke gd.createFromGif with a string pointing to an existing file containing the desired image to return a new image or nil if unable to load the image (most often because the file is corrupt or does not contain a GIF image). You can determine the size of the image with gd.sizeXY.

gd.createFromGd(filename)

gd.createFromGd is called to load images from gd format files. Invoke gd.createFromGd with a string pointing to an existing file containing the desired image to return a new image or nil if unable to load the image (most often because the file is corrupt or does not contain a gd image). You can determine the size of the image with gd.sizeXY. This format is not intended for general purpose use and should never be used to distribute images. Its purpose is solely to allow very fast loading of images.

gd.createFromGd2(filename)

gd.createFromGd2 is called to load images from gd2 format files. Invoke gd.createFromGd2 with a string pointing to an existing file containing the desired image to return a new image or nil if unable to load the image (most often because the file is corrupt or does not contain a gd2 image). You can determine the size of the image with gd.sizeXY. This format is not intended for general purpose use and should never be used to distribute images. Its purpose is solely to allow very fast loading of images.

gd.createFromGd2Part(filename, x, y, w, h)

gd.createFromGd2Part is called to load parts of images from gd2 format files. Invoked in the same way as gd.createFromGd2, but with extra parameters indicating the source (x, y) and width/height of the desired image.

Example:

-- Being base.gd2 a 40x40px image, copies its upper-left part to a new image
local im = gd.createFromGd2Part("base.gd2", 0, 0, 20, 20)

gd.createFromXbm(filename)

gd.createFromXbm is called to load images from monochromatic X bitmap format files. Invoke gd.createFromXbm with a string pointing to an existing file containing the desired image to return a new image or nil if unable to load the image (most often because the file is corrupt or does not contain a XBM image). You can determine the size of the image with gd.sizeXY.

gd.createFromXpm(filename)

gd.createFromXpm is called to load images from color X bitmap format files. Invoke gd.createFromXpm with a string pointing to an existing file containing the desired image to return a new image or nil if unable to load the image (most often because the file is corrupt or does not contain a XPM image). You can determine the size of the image with gd.sizeXY.

gd.createFromJpegStr(string)

gd.createFromJpegStr is called to load truecolor images from strings with JPEG format image data. Invoke gd.createFromJpegStr passing a string with the desired image to return a new truecolor image or nil if unable to load the image (most often because the data is corrupt or does not contain a JPEG image). You can determine the size of the image with gd.sizeXY. The returned image is always a truecolor image.

gd.createFromGifStr(string)

gd.createFromGifStr is called to load palette-based images from strings with GIF format image data. Invoke gd.createFromGifStr passing a string with the desired image to return a new image or nil if unable to load the image (most often because the data is corrupt or does not contain a GIF image). You can determine the size of the image with gd.sizeXY.

gd.createFromPngStr(string)

gd.createFromPngStr is called to load images from strings with PNG format image data. Invoke gd.createFromPngStr passing a string with the desired image to return a new image or nil if unable to load the image (most often because the data is corrupt or does not contain a PNG image). You can determine the size of the image with gd.sizeXY.

If the PNG image being loaded is a truecolor image, the resulting value will refer to a truecolor image. If the PNG image being loaded is a palette or grayscale image, the resulting data will refer to a palette image. gd retains only 8 bits of resolution for each of the red, green and blue channels, and only 7 bits of resolution for the alpha channel. The former restriction affects only a handful of very rare 48-bit color and 16-bit grayscale PNG images. The second restriction affects all semitransparent PNG images, but the difference is essentially invisible to the eye. 7 bits of alpha channel resolution is, in practice, quite a lot.

Example:

-- reads the contents of the file to a string
fp = io.open("picture.png")
str = fp:read("*a")
fp:close()

-- creates an image from the string
local im = gd.createFromPngStr(str)

gd.createFromGdStr(string)

gd.createFromGdStr is called to load images from strings with gd format image data. Invoke gd.createFromGdStr passing a string with the desired image to return a new image or nil if unable to load the image (most often because the data is corrupt or does not contain a gd image). You can determine the size of the image with gd.sizeXY. This format is not intended for general purpose use and should never be used to distribute images. Its purpose is solely to allow very fast loading of images.

gd.createFromGd2Str(string)

gd.createFromGd2Str is called to load images from strings with gd2 format image data. Invoke gd.createFromGd2Str passing a string with the desired image to return a new image or nil if unable to load the image (most often because the data is corrupt or does not contain a gd2 image). You can determine the size of the image with gd.sizeXY. This format is not intended for general purpose use and should never be used to distribute images. Its purpose is solely to allow very fast loading of images.

gd.createFromGd2PartStr(string, x, y, w, h)

gd.createFromGd2PartStr is called to load parts of images from gd2 format strings. Invoked in the same way as gd.createFromGd2Str, but with extra parameters indicating the source (x, y) and width/height of the desired image.

Image output methods

gdImage:png(filename)

Outputs the image to a PNG file with the specified name (overwriting existing files). This method returns false on error (eg. permission denied to overwrite an existing file) and true on success.

Example:

-- creates a new image
local im = gd.createTrueColor(20, 20)

-- ** DO SOME ART HERE **

-- writes the image to a PNG file.
im:png("picture.png")

If you want to check if the writting was succeful:

-- creates a new image
local im = gd.createTrueColor(20, 20)

-- ** DO SOME ART HERE **

if im:png("picture.png") then
  print("Image written to disk")
else
  print("Oops, an error...")
end

gdImage:pngEx(filename, compression_level)

Similiar to gd.png, but allows you to specify the compression level of a PNG image, from 1 to 6 (or -1 for the default compression level of libpng). This method returns false on error (eg. permission denied to overwrite an existing file) and true on success.

gdImage:jpeg(filename, quality)

Outputs the image to a JPEG file with the specified name (overwriting existing files). You must specify the quality of the generated JPEG file from 1 (worst quality, small files) to 100 (best quality, large files). This method returns false on error (eg. permission denied to overwrite an existing file) and true on success.

gdImage:gif(filename)

Outputs the image to a GIF file with the specified name (overwriting existing files). This method returns false on error (eg. permission denied to overwrite an existing file) and true on success.

gdImage:gd(filename)

Outputs the image to a gd format file with the specified name (overwriting existing files). This method returns false on error (eg. permission denied to overwrite an existing file) and true on success. This format is not intended for general purpose use and should never be used to distribute images. Its purpose is solely to allow very fast loading of images.

gdImage:gd2(filename, chunkSize, format)

Outputs the image to a gd2 format file with the specified name (overwriting existing files). This method returns false on error (eg. permission denied to overwrite an existing file) and true on success. You must specify the chunk size (an integer, or 0 for the default) and the file format, which can be gd.GD2_FMT_RAW or gd.GD2_FMT_COMPRESSED. This format is not intended for general purpose use and should never be used to distribute images. Its purpose is solely to allow very fast loading of images.

gdImage:wbmp(filename, fg)

Outputs the image to a WBMP file with the specified name (overwriting existing files). WBMP file support is black and white only. The color index specified by the fg argument is the "foreground", and only pixels of this color will be set in the WBMP file. All other pixels will be considered "background". This method returns false on error (eg. permission denied to overwrite an existing file) and true on success.

gdImage:pngStr()

This method returns the image in the PNG format as a Lua string or nil on error (eg. a corrupted image).

gdImage:pngStrEx(compression_level)

Similiar to gd.pngStr, but allows you to specify the compression level of a PNG image, from 1 to 6 (or -1 for the default compression level of libpng). This method returns nil on error.

gdImage:jpegStr(quality)

This method returns the image in the JPEG format as a Lua string or nil on error (eg. a corrupted image). You must specify the quality of the generated JPEG data from 1 (worst quality, small string) to 100 (best quality, large string).

Example:

-- creates a new image
local im = gd.createTrueColor(20, 20)

-- ** DO SOME ART HERE **
-- writes the image to a PNG file.
im:png("picture.png")

-- writes the image to stdout in the JPEG format
io.write(im:jpegStr(75))

gdImage:gifStr()

This method returns the image in the GIF format as a Lua string or nil on error (eg. a corrupted image).

gdImage:gdStr()

This method returns the image in the gd format as a Lua string or nil on error (eg. a corrupted image).

gdImage:gd2Str(chunkSize, format)

This method returns the image in the gd2 format as a Lua string or nil on error (eg. a corrupted image). You must specify the chunk size (an integer, or 0 for the default) and the data format, which can be gd.GD2_FMT_RAW or gd.GD2_FMT_COMPRESSED. This format is not intended for general purpose use and should never be used to distribute images. Its purpose is solely to allow very fast loading of images.

gdImage:wbmpStr(fg)

This method returns the image in the WBMP format as a Lua string or nil on error (eg. a corrupted image). WBMP format support is black and white only. The color index specified by the fg argument is the "foreground", and only pixels of this color will be set in the WBMP string. All other pixels will be considered "background".

Color manipulation methods

gdImage:colorAllocate(red, green, blue)

colorAllocate() finds the first available color index in the image specified, sets its RGB values to those requested (255 is the maximum for each), and returns the index of the new color table entry, or an RGBA value in the case of a truecolor image; in either case you can then use the returned value as a parameter to drawing methods. When creating a new palette-based image, the first time you invoke this method, you are setting the background color for that image.

In the event that all gd.MAX_COLORS colors (256) have already been allocated, colorAllocate will return nil to indicate failure. (This is not uncommon when working with existing PNG files that already use 256 colors). Note that colorAllocate does not check for existing colors that match your request; see colorExact, colorClosest and colorClosestHWB for ways to locate existing colors that approximate the color desired in situations where a new color is not available.

gdImage:colorAllocateAlpha(red, green, blue, alpha)

colorAllocateAlpha finds the first available color index in the image specified, sets its RGBA values to those requested (255 is the maximum for red, green and blue, and 127 represents full transparency for alpha), and returns the index of the new color table entry, or an RGBA value in the case of a truecolor image; in either case you can then use the returned value as a parameter to drawing methods. When creating a new palette-based image, the first time you invoke this method, you are setting the background color for that image.

In the event that all gd.MAX_COLORS colors (256) have already been allocated, colorAllocateAlpha will return nil to indicate failure. (This is not uncommon when working with existing palette-based PNG files that already use 256 colors). Note that colorAllocateAlpha does not check for existing colors that match your request; see colorExactAlpha and colorClosestAlpha for ways to locate existing colors that approximate the color desired in situations where a new color is not available. Also see colorResolveAlpha.

gdImage:colorClosest(red, green, blue)

colorClosest searches the colors which have been defined thus far in the image specified and returns the index of the color with RGB values closest to those of the request. (Closeness is determined by Euclidian distance, which is used to determine the distance in three-dimensional color space between colors).

If no colors have yet been allocated in the image, colorClosest returns nil.

When applied to a truecolor image, this method always succeeds in returning the desired color.

This method is most useful as a backup method for choosing a drawing color when an image already contains gd.MAX_COLORS (256) colors and no more can be allocated. (This is not uncommon when working with existing PNG files that already use many colors). See colorExact for a method of locating exact matches only.

gdImage:colorClosestAlpha(red, green, blue, alpha)

colorClosestAlpha searches the colors which have been defined thus far in the image specified and returns the index of the color with RGBA values closest to those of the request. (Closeness is determined by Euclidian distance, which is used to determine the distance in four-dimensional color/alpha space between colors).

If no colors have yet been allocated in the image, colorClosestAlpha returns nil.

When applied to a truecolor image, this method always succeeds in returning the desired color.

This method is most useful as a backup method for choosing a drawing color when a palette-based image already contains gd.MAX_COLORS (256) colors and no more can be allocated. (This is not uncommon when working with existing palette-based PNG files that already use many colors). See colorExactAlpha for a method of locating exact matches only.

gdImage:colorClosestHWB(red, green, blue)

colorClosestHWB searches the colors which have been defined thus far in the image specified and returns the index of the color with hue, whiteness and blackness closest to the requested color. This scheme is typically superior to the Euclidian distance scheme used by colorClosest.

If no colors have yet been allocated in the image, colorClosestHWB returns nil.

When applied to a truecolor image, this method always succeeds in returning the desired color.

This method is most useful as a backup method for choosing a drawing color when an image already contains gd.MAX_COLORS (256) colors and no more can be allocated. (This is not uncommon when working with existing PNG files that already use many colors). See colorExact for a method of locating exact matches only.

gdImage:colorExact(red, green, blue)

colorExact searches the colors which have been defined thus far in the image specified and returns the index of the first color with RGB values which exactly match those of the request. If no allocated color matches the request precisely, colorExact returns nil. See colorClosest for a way to find the color closest to the color requested.

When applied to a truecolor image, this method always succeeds in returning the desired color.

gdImage:colorExactAlpha(red, green, blue, alpha)

colorExactAlpha searches the colors which have been defined thus far in the image specified and returns the index of the first color with RGBA values which exactly match those of the request. If no allocated color matches the request precisely, colorExactAlpha returns nil. See colorClosestAlpha for a way to find the color closest to the color requested.

When applied to a truecolor image, this method always succeeds in returning the desired color.

gdImage:colorResolve(red, green, blue)

colorResolve searches the colors which have been defined thus far in the image specified and returns the index of the first color with RGB values which exactly match those of the request. If no allocated color matches the request precisely, then colorResolve tries to allocate the exact color. If there is no space left in the color table then ColorResolve returns the closest color (as in colorClosest). This method always returns an index of a color.

When applied to a truecolor image, this method always succeeds in returning the desired color.

gdImage:colorResolveAlpha(red, green, blue, alpha)

colorResolveAlpha searches the colors which have been defined thus far in the image specified and returns the index of the first color with RGBA values which exactly match those of the request. If no allocated color matches the request precisely, then colorResolveAlpha tries to allocate the exact color. If there is no space left in the color table then colorResolveAlpha returns the closest color (as in colorClosestAlpha). This method always returns an index of a color.

When applied to a truecolor image, this method always succeeds in returning the desired color.

gdImage:colorsTotal()

This method returns the number of colors currently allocated in a palette image. For truecolor images, the result of this call is undefined and should not be used.

gdImage:red(color)

This method returns the red portion of the specified color in the image. This method works for both palette and truecolor images.

gdImage:blue(color)

This method returns the blue portion of the specified color in the image. This method works for both palette and truecolor images.

gdImage:green(color)

This method returns the green portion of the specified color in the image. This method works for both palette and truecolor images.

gdImage:alpha(color)

This method returns the alpha portion of the specified color in the image. This method works for both palette and truecolor images.

gdImage:getTransparent()

This method returns the current transparent color index in the image. If there is no transparent color, getTransparent returns nil.

gdImage:colorTransparent(color)

colorTransparent sets the transparent color index for the specified image to the specified index. To indicate that there should be no transparent color, invoke colorTransparent with a color index of nil (or passing no color index). Note that JPEG images do not support transparency, so this setting has no effect when writing JPEG images.

The color index used should be an index allocated by colorAllocate, whether explicitly invoked by your code or implicitly invoked by loading an image. In order to ensure that your image has a reasonable appearance when viewed by users who do not have transparent background capabilities (or when you are writing a JPEG-format file, which does not support transparency), be sure to give reasonable RGB values to the color you allocate for use as a transparent color, even though it will be transparent on systems that support PNG transparency.

gdImage:colorDeallocate(color)

colorDeallocate marks the specified color as being available for reuse. It does not attempt to determine whether the color index is still in use in the image. After a call to this method, the next call to colorAllocate for the same image will set new RGB values for that color index, changing the color of any pixels which have that index as a result. If multiple calls to colorDeallocate are made consecutively, the lowest-numbered index among them will be reused by the next colorAllocate call.

Query methods

gdImage:boundsSafe(x, y)

boundsSafe returns true if the specified point is within the current clipping rectangle, false if not. The clipping rectangle is set by setClip and defaults to the entire image. This method is intended primarily for use by those who wish to add methods to Lua-GD. All of the drawing functions already clip safely.

gdImage:getPixel(x, y)

getPixel returns the color index of a particular pixel.

gdImage:sizeX()

sizeX returns the width of the image in pixels.

gdImage:sizeY()

sizeY returns the height of the image in pixels.

gdImage:sizeXY()

sizeXY returns the width and the height of the image in pixels. This method has no C equivalent because, unlike Lua, C functions cannot return multiple values.

Example:

local x, y = im:sizeXY()

gdImage:getClip()

Fetches the boundaries of the current clipping rectangle. This method returns four numbers.

Example:

local x1, y1, x2, y2 = im:getClip()

gdImage:setClip(x1, y1, x2, y2)

Establishes a clipping rectangle. Once setClip has been called, all future drawing operations will remain within the specified clipping area, until a new setClip call takes place. For instance, if a clipping rectangle of 25, 25, 75, 75 has been set within a 100x100 image, a diagonal line from 0,0 to 99,99 will appear only between 25,25 and 75,75.

Drawing methods

gdImage:setPixel(x, y, color)

setPixel sets a pixel to a particular color index.

gdImage:line(x1, y1, x2, y2, color)

line is used to draw a line between two endpoints (x1,y1 and x2, y2). The line is drawn using the color index specified. Note that the color index can be an actual color returned by colorAllocate or one of gd.STYLED, gd.BRUSHED or gd.STYLED_BRUSHED.

gdImage:rectangle(x1, y1, x2, y2, color)

rectangle is used to draw a rectangle with the two corners (upper left first, then lower right) specified, using the color index specified.

gdImage:filledRectangle(x1, y1, x2, y2, color)

filledRectangle is used to draw a rectangle with the two corners (upper left first, then lower right) specified, filled using the color index specified.

gdImage:polygon({ { x1, y1 }, { x2, y2 } ... }, color)

polygon is used to draw a polygon with the verticies (at least 3) specified in the table, using the color index specified.

Example:

im = assert(gd.createTrueColor(80, 80))
black = im:colorAllocate(0, 0, 0)
white = im:colorAllocate(255, 255, 255)
im:polygon( { { 10, 10 }, { 10, 20 }, { 20, 20 }, { 20, 10 } }, white)
im:png("out.png")

gdImage:filledPolygon({ { x1, y1 }, { x2, y2 } ... }, color)

polygon is used to fill a polygon with the verticies (at least 3) specified in the table, using the color index specified.

Example:

im = assert(gd.createTrueColor(80, 80))
black = im:colorAllocate(0, 0, 0)
white = im:colorAllocate(255, 255, 255)
im:filledPolygon( { { 30, 30 }, { 30, 40 }, { 40, 40 }, { 40, 30 } }, white)
im:png("out.png")

gdImage:openPolygon({ { x1, y1 }, { x2, y2 } ... }, color)

openPolygon is used to draw a sequence of lines with the verticies (at least 3) specified, using the color index specified. Unlike polygon, the enpoints of the line sequence are not connected to a closed polygon.

Example:

im = assert(gd.createTrueColor(80, 80))
black = im:colorAllocate(0, 0, 0)
white = im:colorAllocate(255, 255, 255)
im:openPolygon( { { 50, 50 }, { 50, 60 }, { 60, 60 }, { 60, 50 } }, white)
im:png("out.png")

gdImage:arc(cx, cy, w, h, s, e, color)

arc is used to draw a partial ellipse centered at the given point, with the specified width and height in pixels. The arc begins at the position in degrees specified by s and ends at the position specified by e. The arc is drawn in the color specified by the last argument. A circle can be drawn by beginning from 0 degrees and ending at 360 degrees, with width and height being equal. e must be greater than s. Values greater than 360 are interpreted modulo 360.

gdImage:filledArc(cx, cy, w, h, s, e, color, style)

filledArc is used to draw a partial ellipse centered at the given point, with the specified width and height in pixels. The arc begins at the position in degrees specified by s and ends at the position specified by e. The arc is filled in the color specified by color. A circle can be drawn by beginning from 0 degrees and ending at 360 degrees, with width and height being equal. e must be greater than s. Values greater than 360 are interpreted modulo 360. The last argument is a sum of the following possibilities: gd.ARC, gd.CHORD, gd.PIE (synonym for gd.CHORD), gd.NO_FILL and gd.EDGED. gd.ARC and gd.CHORD are mutually exclusive; gd.CHORD just connects the starting and ending angles with a straight line, while gd.ARC produces a rounded edge. gd.PIE is a synonym for gd.ARC. gd.NO_FILL indicates that the arc or chord should be outlined, not filled. gd.EDGED, used together with gd.NO_FILL, indicates that the beginning and ending angles should be connected to the center; this is a good way to outline (rather than fill) a 'pie slice'.

gdImage:filledEllipse(cx, cy, w, h, color)

filledEllipse is used to draw an ellipse centered at the given point, with the specified width and height in pixels. The ellipse is filled in the color specified by the last argument.

gdImage:fill(x, y, c)

fill floods a portion of the image with the specified color, beginning at the specified point and flooding the surrounding region of the same color as the starting point. For a way of flooding a region defined by a specific border color rather than by its interior color, see fillToBorder.

The fill color can be gd.TILED, resulting in a tile fill using another image as the tile. However, the tile image cannot be transparent. If the image you wish to fill with has a transparent color index, call setTransparent on the tile image and set the transparent color index to nil to turn off its transparency.

gdImage:fillToBorder(x, y, border_color, color)

fillToBorder floods a portion of the image with the specified color, beginning at the specified point and stopping at the specified border color. For a way of flooding an area defined by the color of the starting point, see fill.

The border color cannot be a special color such as gd.TILED; it must be a proper solid color. The fill color can be, however.

Text drawing methods

gdImage:string(font, x, y, string, color)

This method draws the string in the fourth argument on the image using one of the standard gd fonts (gd.FONT_TINY, gd.FONT_SMALL, gd.FONT_MEDIUM, gd.FONT_LARGE or gd.FONT_GIANT) from left to right, starting from the (x, y) point and with the color specified by the fifth argument. The string must have only ISO-8859-1 characters (you should use gd.stringFT and True Type fonts for drawing Unicode strings.

Example:

im = gd.create(140, 80)
white = im:colorAllocate(255, 255, 255)
black = im:colorAllocate(0, 0, 0)
im:string(gd.FONT_TINY, 10, 20, "TINY", black)
im:string(gd.FONT_SMALL, 10, 30, "SMALL", black)
im:string(gd.FONT_MEDIUM, 10, 45, "MEDIUM", black)
im:string(gd.FONT_LARGE, 10, 58, "LARGE", black)
im:string(gd.FONT_GIANT, 10, 75, "GIANT", black)
im:png("out.png")

gdImage:stringUp(fontname, x, y, string, color)

Similar to gd.string but the string will be drawn vertically (rotated 90 degrees), from bottom to up, starting from the (x, y) point. The string must have only ISO-8859-1 characters. If you want use Unicode characters or other rotations than 90°, you should use gd.stringFT and True Type fonts.

gdImage:stringFT(color, fontname, ptsize, angle, x, y, string)

stringFT draws a string of anti-aliased characters on the image using the FreeType library to render user-supplied TrueType fonts. The string is anti-aliased, meaning that there should be fewer "jaggies" visible. The fontname is the full pathname to a TrueType font file, or a font face name if the GDFONTPATH environment variable have been set intelligently. In the absence of a full path, the font face name may be presented with or without extension. Font names can also be fontconfig patterns (see gd.useFontConfig) so, the library will automatically use fonts from your operating system.

The string argument is considered to be encoded via the UTF-8 standard; also, HTML entities are supported, including decimal, hexadecimal, and named entities. Those who are passing ordinary ASCII strings may have difficulty with the & character unless encoded correctly as & but should have no other difficulties.

The string may be arbitrarily scaled (ptsize) and rotated (angle in radians). The direction of rotation is counter-clockwise, with 0 radians (0 degrees) at 3 o'clock and PI/2 radians (90 degrees) at 12 o'clock (you should use math.rad to convert degrees to radians). The string is rendered in the color indicated by the color index. Use the negative of the desired color index to disable anti-aliasing.

This method return eight values with the limits of the rendered text on sucess or nil on failure. The following code show how to use them to draw a bounding rectangle arround the text.

im = gd.createTrueColor(100, 100)
black = im:colorAllocate(0, 0, 0)
white = im:colorAllocate(255, 255, 255)
blue  = im:colorAllocate(0, 0, 240)
im:filledRectangle(0, 0, 100, 100, black)
llx, lly, lrx, lry, urx, ury, ulx, uly = im:stringFT(white, "Vera.ttf", 20, math.rad(45), 20, 90, "Lua-GD")
im:polygon({ {llx, lly}, {lrx, lry}, {urx, ury}, {ulx, uly} }, blue)

Variables used above can be translated as follows. The points are relative to the text regardless of the angle, so "upper left" means in the top left-hand corner seeing the text horizontally.

# Name Meaning
1 llx lower left corner, X position
2 lly lower left corner, Y position
3 lrx lower right corner, X position
4 lry lower right corner, Y position
5 urx upper right corner, X position
6 ury upper right corner, Y position
7 ulx upper left corner, X position
8 uly upper left corner, Y position

Also, there is a way to get these values before drawing on the image passing nil as the first argument of gd.stringFT (note the absence of the colon notation!), as follows. This is a relatively cheap operation if followed by a rendering of the same string, because of the caching of the partial rendering during bounding rectangle calculation.

llx, lly, lrx, lry, urx, ury, ulx, uly = gd.stringFT(nil, white, "Vera.ttf", 20, math.rad(45), 20, 90, "Lua-GD")

gdImage:stringFTEx(color, fontname, ptsize, angle, x, y, string, extra)

This is an extended version of stringFT that accepts a table as an extra argument, which allows you to pass some parameters to the rendering engine. The fields currently available are show bellow:

Field name Type Default Usage
linespacing float 1.05 Allows you to set the space between lines when rendering multiple lines. A line spacing of 1.0 is the minimum to guarantee that lines of text do not collide.
charmap indexed gd.FTEX_Unicode Allows you to set a specific character encoding schema, which can be any of gd.FTEX_Unicode, gd.FTEX_Shift_JIS, or gd.FTEX_Big5. It is useful when a font offers more than one of Unicode, Shift_JIS, and Big5. If you do not specify one, Unicode will be tried first. If the preferred character mapping is not found in the font, other character mappings are attempted.
hdpi integer 96 Sets the horizontal resolution passed to the FreeType engine.
vdpi integer 96 Sets the vertical resolution passed to the FreeType engine.
disable_kerning boolean false If fontconfig is available, gd will normally attempt to apply kerning tables to adjust the relative positions of consecutive characters more ideally for that pair of characters. This field allows you to turn this feature off.
xshow boolean false Request gd to return a vector of individual character position advances, occasionally useful in applications that must know exactly where each character begins. This is returned as a string with values separated by spaces.
return_font_path_name boolean false Returns the path to the font used to render the text. This is useful because gd are capable of selecting a font automatically based on a fontconfig font pattern when fontconfig is available.
fontconfig boolean false gd can use fontconfig to resolve font names, including fontconfig patterns, if this field is set to true. As a convenience, this behavior can also be made the default by calling gd.useFontConfig with a true value.

This method also returns the same values than stringFT, more two aditional ones if the fields xshow or return_font_path_name are set to true. See the following example:

llX, llY, lrX, lrY, urX, urY, ulX, ulY = 
  im:stringFTEx(blue, "Vera", 20, 0, 50, 50, "Lua-GD",
    { hdpi = 40, vdpi = 20 } )

llX, llY, lrX, lrY, urX, urY, ulX, ulY, pos = 
  im:stringFTEx(blue, "Vera", 20, 0, 50, 150, "Lua-GD",
    { hdpi = 40, vdpi = 20, xshow = true } )

llX, llY, lrX, lrY, urX, urY, ulX, ulY, fontpath = 
  im:stringFTEx(blue, "Vera", 20, 0, 50, 250, "Lua-GD",
    { hdpi = 40, vdpi = 20, return_font_path_name = true } )

llX, llY, lrX, lrY, urX, urY, ulX, ulY, pos, fontpath = 
  im:stringFTEx(blue, "Vera", 20, 0, 50, 350, "Lua-GD",
    { hdpi = 40, vdpi = 20, xshow = true, return_font_path_name = true } )

gdImage:stringFTCircle(cx, cy, radius, textRadius, fillPortion, fontname, points, top, bottom, color)

Draws the text strings specified by top and bottom on the image, curved along the edge of a circle of radius radius, with its center at cx and cy. top is written clockwise along the top; bottom is written counterclockwise along the bottom. textRadius determines the "height" of each character; if textRadius is 1/2 of radius, characters extend halfway from the edge to the center. fillPortion varies from 0 to 1.0, with useful values from about 0.4 to 0.9, and determines how much of the 180 degrees of arc assigned to each section of text is actually occupied by text; 0.9 looks better than 1.0 which is rather crowded. fontname is a freetype font; see gd.stringFT. points is passed to the freetype engine and has an effect on hinting; although the size of the text is determined by radius, textRadius, and fillPortion, you should pass a point size that "hints" appropriately -- if you know the text will be large, pass a large point size such as 24.0 to get the best results. color can be any color, and may have an alpha component, do blending, etc.

Font configuration methods

gd.useFontConfig(bool)

gd has the ability to use fontconfig patterns rather than font file names as parameters to gd.stringFT and gd.stringFTCircle. For backwards compatibility reasons, the fontlist parameter to those functions is still expected to be a full or partial font file path name or list thereof by default. However, as a convenience, a single call to gd.useFontConfig with a true parameter configures Lua-GD to expect the fontlist parameter to be a fontconfig pattern. Otherwise, calling gd.useFontConfig with a false parameter will disable the fontconfig patters.

gd.fontCacheSetup()

This function initializes the font cache for freetype text output functions such as gd.stringFT. If this function is not called by the programmer, it is invoked automatically on the first truetype text output call, which is perfectly safe unless the application is multithreaded (either using LuaThreads or running Lua from a different thread in your host program which also uses gd from the C API) . Multithreaded applications should directly invoke this function before allowing any thread to use freetype text output. You don't need to call this functions if you are using Lua coroutines because any calls from Lua to C API ara atomic. This function returns true on success or false if the freetype library fails to initialize.

gd.fontCacheShutdown()

This function releases the memory used by the freetype font cache and the text output mutex. Applications that use Lua-GD for their entire lifetime, then exit, need not call this function. This function has no return value.

Image copying, resizing and transformation methods

gd.copy(dstImage, srcImage, dstX, dstY, srcX, srcY, w, h)
dstImage:copy(srcImage, dstX, dstY, srcX, srcY, w, h)

gd.copy is used to copy a rectangular portion of one image to another image (For a way of stretching or shrinking the image in the process, see gd.copyResized).

The dstImage argument is the destination image to which the region will be copied (you can use the colon notation for it). The srcImage argument is the source image from which the region is copied. The dstX and dstY arguments specify the point in the destination image to which the region will be copied. The srcX and srcY arguments specify the upper left corner of the region in the source image. The w and h arguments specify the width and height of the region.

When you copy a region from one location in an image to another location in the same image, gd.copy will perform as expected unless the regions overlap, in which case the result is unpredictable.

Important note on copying between images: since different images do not necessarily have the same color tables, pixels are not simply set to the same color index values to copy them. If the destination image is a palette image, this method will use the gd.colorResolve method to determine the best color available.

gd.copyResized(dstImage, srcImage, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH)
dstImage:copyResized(srcImage, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH)

gd.copyResized is used to copy a rectangular portion of one image to another image. The X and Y dimensions of the original region and the destination region can vary, resulting in stretching or shrinking of the region as appropriate (For a simpler version of this method which does not deal with resizing, see gd.copy).

The dstImage argument is the destination image to which the region will be copied. The srcImage argument is the source image from which the region is copied. The dstX and dstY arguments specify the point in the destination image to which the region will be copied. The srcX and srcY arguments specify the upper left corner of the region in the source image. The dstW and dstH arguments specify the width and height of the destination region. The srcW and srcH arguments specify the width and height of the source region and can differ from the destination size, allowing a region to be scaled during the copying process.

When you copy a region from one location in an image to another location in the same image, gd.copyResized will perform as expected unless the regions overlap, in which case the result is unpredictable.

Important note on copying between images: since different images do not necessarily have the same color tables, pixels are not simply set to the same color index values to copy them. If the destination image is a palette image, this method will use the gd.colorResolve method to determine the best color available.

gd.copyResampled(dstImage, srcImage, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH)
dstImage:copyResampled(srcImage, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH)

gd.copyResampled is used to copy a rectangular portion of one image to another image, smoothly interpolating pixel values so that, in particular, reducing the size of an image still retains a great deal of clarity. The X and Y dimensions of the original region and the destination region can vary, resulting in stretching or shrinking of the region as appropriate. (For a simpler version of this method which does not deal with resizing, see gd.copy. For a version which does not interpolate pixel values, see gd.copyResized).

Pixel values are only interpolated if the destination image is a truecolor image. Otherwise, gd.copyResized is automatically invoked.

The dstImage argument is the destination image to which the region will be copied. The srcImage argument is the source image from which the region is copied. The dstX and dstY arguments specify the point in the destination image to which the region will be copied. The srcX and srcY arguments specify the upper left corner of the region in the source image. The dstW and dstH arguments specify the width and height of the destination region. The srcW and srcH arguments specify the width and height of the source region and can differ from the destination size, allowing a region to be scaled during the copying process.

When you copy a region from one location in an image to another location in the same image, gd.copyResampled will perform as expected unless the regions overlap, in which case the result is unpredictable. If this presents a problem, create a scratch image in which to keep intermediate results.

Important note on copying between images: since different images do not necessarily have the same color tables, pixels are not simply set to the same color index values to copy them. If the destination image is a palette image, this method will use the gd.colorResolve method to determine the best color available.

gd.copyRotated(dstImage, srcImage, dstX, dstY, srcX, srcY, srcW, srcH, ang)
dstImage:copyRotated(srcImage, dstX, dstY, srcX, srcY, srcW, srcH, ang)

gd.copyRotated is used to copy a rectangular portion of one image to another image, or to another region of the same image. The srcX and srcY coordinates specify the upper left corner of the source area; however, the dstX and dstY coordinates specify the center of the destination area. This important distinction is made because the rotated rectangle may may or may not be parallel to the X and Y axes. The destination coordinates may be floating point, as the center of the desired destination area may lie at the center of a pixel (0.5 pixels) rather than its upper left corner. The angle specified is an integer number of degrees, between 0 and 360, with 0 degrees causing no change, and counterclockwise rotation as the angle increases.

When you copy a region from one location in an image to another location in the same image, gd.copyRotated will perform as expected unless the regions overlap, in which case the result is unpredictable. If this presents a problem, create a scratch image in which to keep intermediate results.

Important note on copying between images: since different images do not necessarily have the same color tables, pixels are not simply set to the same color index values to copy them. If the destination image is a palette image, this method will use the gd.colorRotated method to determine the best color available.

gd.copyMerge(dstImage, srcImage, dstX, dstY, srcX, srcY, w, h, pct)
dstImage:copyMerge(srcImage, dstX, dstY, srcX, srcY, w, h, pct)

gd.copyMerge is almost identical to gd.copy, except that it 'merges' the two images by an amount specified in the last parameter. If the last parameter is 100, then it will method identically to gd.copy - the source image replaces the pixels in the destination.

If, however, the pct parameter is less than 100, then the two images are merged. With pct = 0, no action is taken.

This feature is most useful to 'highlight' sections of an image by merging a solid color with pct = 50.

gd.copyMergeGray(dstImage, srcImage, dstX, dstY, srcX, srcY, w, h, pct)
dstImage:copyMergeGray(srcImage, dstX, dstY, srcX, srcY, w, h, pct)

gd.copyMergeGray is almost identical to gd.copyMerge, except that when merging images it preserves the hue of the source by converting the destination pixels to grey scale before the copy operation.

gd.paletteCopy(dstImage, srcImage)
dstImage:paletteCopy(srcImage)

gd.paletteCopy copies a palette from one image to another, attempting to match the colors in the target image to the colors in the source palette.

gdImage:squareToCircle(radius)

Returns a new image of width and height radius * 2, in which the X axis of the original has been remapped to theta (angle) and the Y axis of the original has been remapped to rho (distance from center). This is known as a "polar coordinate transform". The image MUST be square, but can have any size.

gdImage:sharpen(pct)

Sharpens the specified image. pct is a sharpening percentage, and can be greater than 100. Silently does nothing to non-truecolor images. Silently does nothing for pct < 0. Transparency/alpha channel are not altered.

gdImage:trueColorToPalette(dither, colorsWanted)

This method converts a truecolor image to a palette-based image, using a high-quality two-pass quantization routine. If dither is set to true, the image will be dithered to approximate colors better, at the expense of some obvious "speckling". colorsWanted, an integer value, can be anything up to 256. If the original source image includes photographic information or anything that came out of a JPEG, 256 is strongly recommended. 100% transparency of a single transparent color in the original truecolor image will be preserved. There is no other support for preservation of alpha channel or transparency in the destination image.

For best results, don't use this method -- write real truecolor PNGs and JPEGs. The disk space gain of conversion to palette is not great (for small images it can be negative) and the quality loss is ugly.

GIF animation methods

gdImage:gifAnimBegin(filename, globalCM, loops)

This method must be called as the first method when creating a GIF animation in a file on the disk. It writes the correct GIF file headers to file name filename and prepares for frames to be added for the animation. The image argument is not used to produce an image frame to the file, it is only used to establish the GIF animation frame size, interlacing options and the color palette. gd.gifAnimAdd is used to add the first and subsequent frames to the animation, and the animation must be terminated by calling gd.gifAnimEnd, passing the same file name.

The GlobalCM flag indicates if a global color map (or palette) is used in the GIF89A header. A true value specifies that a global color map should be used to reduce the size of the animation. Of course, if the color maps of individual frames differ greatly, a global color map may not be a good idea, so you should use globalCM = false.

If loops is 0 or greater, the Netscape 2.0 extension for animation loop count is written. 0 means infinite loop count. -1 means that the extension is not added which results in no looping. -1 is the default.

gdImage:gifAnimBeginStr(globalCM, loops)

This method must be called as the first method when creating a GIF animation in memory. It returns the correct GIF file headers as an Lua string and prepares for frames to be added for the animation. The image argument is not used to produce an image frame to the file, it is only used to establish the GIF animation frame size, interlacing options and the color palette. New frames must be created with the method gd.gifAnimAddStr and concatened to this one. Finally, one last frame, generated with the method gd.gifAnimEndStr, must be concatened to finish the animation.

The GlobalCM flag indicates if a global color map (or palette) is used in the GIF89A header. A true value specifies that a global color map should be used to reduce the size of the animation. Of course, if the color maps of individual frames differ greatly, a global color map may not be a good idea, so you should use globalCM = false.

If loops is 0 or greater, the Netscape 2.0 extension for animation loop count is written. 0 means infinite loop count. -1 means that the extension is not added which results in no looping. -1 is the default.

gdImage:gifAnimAdd(filename, localCM, leftOfs, topOfs, delay, disposal [, previm])

This method writes GIF animation frames to the file specified by filename, which was created with gd.gifAnimBegin. With leftOfs and topOfs you can place this frame in different offset than (0, 0) inside the image screen as defined in gd.gifAnimBegin. Delay between the previous frame and this frame is in 1/100s units. Disposal is usually gd.DISPOSAL_NONE, meaning that the pixels changed by this frame should remain on the display when the next frame begins to render, but can also be gd.DISPOSAL_UNKNOWN (not recommended), gd.DISPOSAL_RESTORE_BACKGROUND (restores the first allocated color of the global palette), or gd.DISPOSAL_RESTORE_PREVIOUS (restores the appearance of the affected area before the frame was rendered). Only gd.DISPOSAL_NONE is a sensible choice for the first frame. If previm is passed, the built-in GIF optimizer will always use gd.DISPOSAL_NONE regardless of the disposal parameter.

Setting the localCM flag to true adds a local palette for this image to the animation. Otherwise the global palette is assumed and the user must make sure the palettes match. Use gd.paletteCopy to do that.

Automatic optimization is activated by giving the previous image as a parameter. This method then compares the images and only writes the changed pixels to the new frame in animation. The disposal parameter for optimized animations must be set to gd.DISPOSAL_NONE, also for the first frame. leftOfs and topOfs parameters are ignored for optimized frames. To achieve good optimization, it is usually best to use a single global color map. To allow gd.gifAnimAdd to compress unchanged pixels via the use of a transparent color, the image must include a transparent color.

gdImage:gifAnimAddStr(localCM, leftOfs, topOfs, delay, disposal [, previm])

This method returns GIF animation frames as Lua strings to be concatenated to headers which was created with gd.gifAnimBeginStr. With leftOfs and topOfs you can place this frame in different offset than (0, 0) inside the image screen as defined in gd.gifAnimBegin. Delay between the previous frame and this frame is in 1/100s units. Disposal is usually gd.DISPOSAL_NONE, meaning that the pixels changed by this frame should remain on the display when the next frame begins to render, but can also be gd.DISPOSAL_UNKNOWN (not recommended), gd.DISPOSAL_RESTORE_BACKGROUND (restores the first allocated color of the global palette), or gd.DISPOSAL_RESTORE_PREVIOUS (restores the appearance of the affected area before the frame was rendered). Only gd.DISPOSAL_NONE is a sensible choice for the first frame. If previm is passed, the built-in GIF optimizer will always use gd.DISPOSAL_NONE regardless of the disposal parameter.

Setting the localCM flag to true adds a local palette for this image to the animation. Otherwise the global palette is assumed and the user must make sure the palettes match. Use gd.paletteCopy to do that.

Automatic optimization is activated by giving the previous image as a parameter. This method then compares the images and only writes the changed pixels to the new frame in animation. The disposal parameter for optimized animations must be set to gd.DISPOSAL_NONE, also for the first frame. leftOfs and topOfs parameters are ignored for optimized frames. To achieve good optimization, it is usually best to use a single global color map. To allow gd.gifAnimAdd to compress unchanged pixels via the use of a transparent color, the image must include a transparent color.

gdImage:gifAnimEnd(filename)

Finishes a GIF animation properly by writing a semicolon character (;) to the output file. You must call this method (or write the semicolon by yourself) to create valid animations.

gdImage:gifAnimEndStr()

Returns a semicolon character (;) as a Lua string, which must be concatened as the last element of an animation created with gd.gifAnimBeginStr and gd.gifAnimAddStr. Of course, you can concatenate a semicolon by yourself, but this is a more explicit way to finish the animation.

Examples

CGI Web Counter

#!/usr/bin/env lua
-- counter.lua -- a web counter in Lua!
-- (c) 2004 Alexandre Erwin Ittner

require "gd"

datafile = "counter.txt"
fp = io.open(datafile, "r+")
if fp then
  cnt = tonumber(fp:read("*l")) or 0
  fp:seek("set", 0)
else
  cnt = 0
  fp = io.open(datafile, "w")
  assert(fp)
end
cnt = cnt + 1
fp:write(cnt .."\n")
fp:close()

sx = math.max(string.len(tostring(cnt)), 1) * 8
im = gd.create(sx, 15)
-- first allocated color defines the background.
white = im:colorAllocate(255, 255, 255)
im:colorTransparent(white)
black = im:colorAllocate(0, 0, 0)
im:string(gd.FONT_MEDIUM, 1, 1, cnt, black)

print("Content-type: image/png\n")
io.write(im:pngStr())

CGI Analog clock

Clock Example output
#!/usr/bin/env lua

-- a cgi script that draws an analog clock with lua and lua-gd
-- (c) 2004 Alexandre Erwin Ittner

require "gd"

function createClock(size, hours, minutes)
  local im = gd.createTrueColor(size, size)
  local white = im:colorAllocate(255, 255, 255)
  local gray = im:colorAllocate(128, 128, 128)
  local black = im:colorAllocate(0, 0, 0)
  local blue = im:colorAllocate(0, 0, 128)
  local cxy = size/2

  im:filledRectangle(0, 0, size, size, white)
  im:setThickness(math.max(1, size/100))
  im:arc(cxy, cxy, size, size, 0, 360, black)

  local ang = 0
  local rang, gsize
  while ang < 360 do
    rang = math.rad(ang)
    if math.mod(ang, 90) == 0 then
      gsize = 0.75
    else
      gsize = 0.85
    end
    im:line(
      cxy + gsize * cxy * math.sin(rang),
      size - (cxy + gsize * cxy * math.cos(rang)),
      cxy + cxy * 0.9 * math.sin(rang),
      size - (cxy + cxy * 0.9 * math.cos(rang)),
      gray)
    ang = ang + 30
  end

  im:setThickness(math.max(1, size/50))
  im:line(cxy, cxy,
    cxy + 0.45 * size * math.sin(math.rad(6*minutes)),
    size - (cxy + 0.45 * size * math.cos(math.rad(6*minutes))),
    blue)

  im:setThickness(math.max(1, size/25))
  rang = math.rad(30*hours + minutes/2)
  im:line(cxy, cxy, 
    cxy + 0.25 * size * math.sin(rang),
    size - (cxy + 0.25 * size * math.cos(rang)),
    blue)

  im:setThickness(1)
  local sp = math.max(1, size/20)
  im:filledArc(cxy, cxy, sp, sp, 0, 360, black, gd.ARC)

  return im
end

dh = os.date("*t")
im = createClock(100, dh.hour, dh.min)

print("Content-type: image/png")
print("Refresh: 60")            -- Ask browser to reload the image after 60s
print("Pragma: no-cache")       -- Can mozilla understand this?
print("Expires: Thu Jan 01 00:00:00 UTC 1970")  -- Marks as expired
print("")

io.write(im:pngStr())

The Sierpinski triangle

The Sierpinski triangle
#!/usr/bin/env lua
-- Draws the famous Sierpinski triangle with lua-gd

require "gd"

size = 250
im = gd.createPalette(size, size)
white = im:colorAllocate(255, 255, 255)
black = im:colorAllocate(0, 0, 0)

m = {}
m[math.floor(size/2)] = true

for i = 1, size do
  n = {}
  for j = 1, size do
    if m[j] then
      im:setPixel(j, i, black)
      n[j+1] = not n[j+1]
      n[j-1] = not n[j-1]
    end
  end
  m = n
end

im:png("sierpinski.png")

Using Freetype, Fontconfig and TrueType fonts

Fontconfig Example output
-- The fonts used in this example comes with Microsoft operating systems 
-- and can be downloaded from http://corefonts.sourceforge.net

require "gd"

im = gd.createTrueColor(220, 190)
white = im:colorAllocate(255, 255, 255)
black = im:colorAllocate(0, 0, 0)
x, y = im:sizeXY()
im:filledRectangle(0, 0, x, y, white)

gd.useFontConfig(true)
im:stringFT(black, "Arial", 20, 0, 10, 30, "Standard Arial")
im:stringFT(black, "Arial:bold", 20, 0, 10, 60, "Bold Arial")
im:stringFT(black, "Arial:italic", 20, 0, 10, 90, "Italic Arial")
im:stringFT(black, "Arial:bold:italic", 20, 0, 10, 120, "Italic Bold Arial")
im:stringFT(black, "Times New Roman", 20, 0, 10, 150, "Times New Roman")
im:stringFT(black, "Comic Sans MS", 20, 0, 10, 180, "Comic Sans MS")

im:png("out.png")

GIF animation

A GIF animation
require "gd"

im = gd.createPalette(120, 120)
assert(im)

black = im:colorAllocate(0, 0, 0)
blue = {}
for i = 1, 20 do
  blue[i] = im:colorAllocate(0, 0, 120+6*i)
end

fp = io.open("out.gif", "w")
assert(fp, "Failed to open file for writting")

fp:write(im:gifAnimBeginStr(true, 0))

for i = 1, 20 do
  tim = gd.createPalette(120, 120)
  tim:paletteCopy(im)
  tim:arc(60, 60, 6*i, 6*i, 0, 360, blue[21-i])
  fp:write(tim:gifAnimAddStr(false, 0, 0, 5, gd.DISPOSAL_NONE))
end

fp:write(gd.gifAnimEndStr())
fp:close()

A Steganography Application

Original test image. Image with a staganographic message Resulting image from 'steg.lua diff'
Original test image. Image with a staganographic message (the message cause no visible changes). Resulting image from "steg.lua diff" showing, in color, the pixels changed to store the message.
#/usr/bin/env lua
--[[
                      Steganography with Lua-GD

Steganography is the technique of writing hidden messages in such a way
that no one apart from the intended recipient knows of the existence of
the message; this is in contrast to cryptography, where the existence
of the message is clear, but the meaning is obscured. Generally a
steganographic message will appear to be something else, like a shopping
list, an article, a picture, or some other "cover" message. In the
digital age, steganography works by replacing bits of useless or unused
data in regular computer files (such as graphics, sound, text, HTML, or
even floppy disks) with bits of different, invisible information. This
hidden information can be plain text, cipher text or even images.


                           A Simple Example

If Alice wants to send a secret message to Bob through an insecure
channel, she can use some encryption software (like GnuPG) to encrypt
the message with Bob's public key. It's a good solution because no
one unless Bob will be able to read the message. She can also sign the
message so Bob will know that the message really comes from her. BUT,
a potential attacker will know that a ciphered message was sent. If the
attacker has control over the communication channel, he might block the
message in some way that Bob will never receive it. If Alice also HIDES
the ciphertext in an unsuspected piece of information (like a photo of her
cat) the attacker will not detect it and the message will arrive to Bob.

This program will help Alice to hide some arbitrary text in a PNG image by
replacing the least significant bits of each color channel of some pixels
with bits from the encrypted message. PNG or other loseless compression
algorithm are mandatory here, since compressing the image with a lossy
algorithm will destroy the stored information. The maximum length of the
message is limited by the image's size (each byte needs 8 color channels or
2 pixels and 2 channels from the next pixel). So, the image must have at
least "ceil((length+1)*8/3)" pixels (the extra byte is the NUL marker for
the end of the string). So, if Alice's message is "Meet me in the secret
place at nine o'clock.", she will encrypt and sign it to something like
"PyJYDpz5LCOSHPiXDvLHmVzxLV8qS7EFvZnoo1Mxk+BlT+7lMjpQKs" (imagine Alice's
cat walking in you keyboard :). This is the ciphertext that will be sent
to Bob through the image.

The following table shows what happens to the first eight pixels from
the image when mixed to the first three bytes from the encrypted message:


         +-----+---+----------+-----------------+----------+
         | Pix | C | Orig img |     Message     | New img  |
         |  #  |   |   bits   | Chr | Dec | Bin |   bits   |
         +-----+---+----------+-----+-----+-----+----------+
         |     | R | 01010010 |     |     |  0  | 01010010 |
         |  1  | G | 00101010 |     |     |  1  | 00101011 |
         |_____| B | 00010101 |     |     |  0  | 00010100 |
         |     | R | 11100100 |  P  | 080 |  1  | 11100101 |
         |  2  | G | 00100100 |     |     |  0  | 00100100 |
         |_____| B | 01001111 |     |     |  0  | 01001110 |
         |     | R | 01010010 |     |     |  0  | 01010010 |
         |  3  | G | 00101110 |_____|_____|__0__| 00101110 |
         |_____| B | 00111001 |     |     |  0  | 00111000 |
         |     | R | 10010110 |     |     |  1  | 10010111 |
         |  4  | G | 01011101 |     |     |  1  | 01011101 |
         |_____| B | 00100101 |  y  | 121 |  1  | 00100101 |
         |     | R | 01001001 |     |     |  1  | 01001001 |
         |  5  | G | 10110110 |     |     |  0  | 10110110 |
         |_____| B | 00010101 |     |     |  0  | 00010100 |
         |     | R | 00110100 |_____|_____|__1__| 00110101 |
         |  6  | G | 01000111 |     |     |  0  | 01000110 |
         |_____| B | 01001000 |     |     |  1  | 01001001 |
         |     | R | 01010110 |     |     |  0  | 01010110 |
         |  7  | G | 00011001 |     |     |  0  | 00011000 |
         |_____| B | 10010100 |  J  | 074 |  1  | 10010101 |
         |     | R | 00010101 |     |     |  0  | 00010100 |
         |  8  | G | 01011010 |     |     |  1  | 01011011 |
         |     | B | 01010001 |     |     |  0  | 01010000 |
         +-----+---+----------+-----+-----+-----+----------+


When Bob wants to read the message he will extract the least significant
bit (LSB) from each color channel from some pixels of the image and
join them to get the original ciphertext. A NULL character (ASCII #0)
will mark the end of the message within the image, so he will know when
to stop. Of course, this program will also do this boring job for Bob.

--]]

require "gd"

function getLSB(n)
  return math.mod(n, 2) ~= 0
end


-- Bizarre way to do some bit-level operations without bitlib.
function setLSB(n, b)
  if type(b) == "number" then
    if b == 0 then
      b = false
    else
      b = true
    end
  end
  if getLSB(n) then
    if b then
      return n
    elseif n > 0 then
      return n - 1
    else
      return n + 1
    end
  else
    if not b then
      return n
    elseif n > 0 then
      return n - 1
    else
      return n + 1
    end
  end
end


function intToBitArray(n)
  local ret = {}
  local i = 0
  while n ~= 0 do
    ret[i] = getLSB(n)
    n = math.floor(n/2)
    ret.size = i
    i = i + 1
  end 
  return ret
end


function printBitArray(a)
  local i
  for i = a.size,0,-1 do
    if a[i] then
      io.write("1")
    else    
      io.write("0")
    end
  end
end


function mergeMessage(im, msg)
  local w, h = im:sizeXY()
  msg = msg .. string.char(0)
  local len = string.len(msg)
  if h * w < len * 8 then
    return nil
  end
  local x, y = 0, 0
  local oim = gd.createTrueColor(w, h)
  local i = 1
  local a2, c, nc, chr
  local a = {}
  local s, e = 1, 1
  local rgb = {}

  while y < h do
    c = im:getPixel(x, y)
    rgb.r = im:red(c)
    rgb.g = im:green(c)
    rgb.b = im:blue(c)
    if i <= len and  e - s < 3 then
      a2 = intToBitArray(string.byte(string.sub(msg, i, i)))
      for cnt = 7,0,-1 do
        a[e+7-cnt] = a2[cnt]
      end
      i = i + 1
      e = e + 8
    end
    if e - s > 0 then
      rgb.r = setLSB(rgb.r, a[s])
      a[s] = nil
      s = s + 1
    end
    if e - s > 0 then
      rgb.g = setLSB(rgb.g, a[s])
      a[s] = nil
      s = s + 1
    end
    if e - s > 0 then
      rgb.b = setLSB(rgb.b, a[s])
      a[s] = nil
      s = s + 1
    end
    nc = oim:colorResolve(rgb.r, rgb.g, rgb.b)
    oim:setPixel(x, y, nc)
    x = x + 1
    if x == w then
      x = 0
      y = y + 1
    end
  end
  return oim, len*8, w*h
end


function getMessage(im)
  local msg = {}
  local w, h = im:sizeXY()
  local x, y = 0, 0
  local a = {}
  local s, e = 1, 1
  local b = 0
  local c
  while y <= h do
    c = im:getPixel(x, y)
    a[e] = getLSB(im:red(c))
    a[e+1] = getLSB(im:green(c))
    a[e+2] = getLSB(im:blue(c))
    e = e + 2
    if e - s >= 7 then
      b = 0
      for p = s, s+7 do
        b = b * 2
        if a[p] then
          b = b + 1
        end
        a[p] = nil
      end
      s = s + 8
      if b == 0 then
        return table.concat(msg)
      else
        msg[#msg+1] = string.char(b)
      end
    end
    e = e + 1
    x = x + 1
    if x == w then
      x = 0
      y = y + 1
    end
  end
  return table.concat(msg)
end


function compare(fimg1, fimg2)
  local im1 = gd.createFromPng(fimg1)
  if not im1 then
    print("ERROR: " .. fimg1 .. " bad PNG data.")
    os.exit(1)
  end
  local im2 = gd.createFromPng(fimg2)
  if not im2 then
    print("ERROR: " .. fimg2 .. " bad PNG data.")
    os.exit(1)
  end
  local w1, h1 = im1:sizeXY()
  local w2, h2 = im2:sizeXY()
  if w1 ~= w2 or h1 ~= h2 then
    print("ERROR: Images have different sizes.")
    os.exit(1)
  end
  local oim = gd.createTrueColor(w1, h1)
  local x, y = 0, 0
  local c1, c2, oc, f, fc
  while y < h1 do
    c1 = im1:getPixel(x, y)
    c2 = im2:getPixel(x, y)
    if im1:red(c1) ~= im2:red(c2)
    or im1:green(c1) ~= im2:green(c2)
    or im1:blue(c1) ~= im2:blue(c2) then
      oc = oim:colorResolve(im2:red(c2), im2:green(c2), im2:blue(c2))
      oim:setPixel(x, y, oc)
    else
      f = math.floor((im1:red(c1) + im1:green(c1) + im1:blue(c1))/6.0)
      fc = oim:colorResolve(f, f, f)
      oim:setPixel(x, y, fc)
    end
    x = x + 1
    if x == w1 then
      x = 0
      y = y + 1
    end
  end
  return oim
end
    

function usage()
  print("Usage:")
  print(" lua steg.lua hide <input file> <output file>")
  print(" lua steg.lua show <input file>")
  print(" lua steg.lua diff <input file 1> <input file 2> <output file>")
  print("")
  print(" hide - Reads a message from stdin and saves into <output file>.")
  print(" show - Reads a message from <input file> and prints it to stdout.")
  print(" diff - Compares two images and writes the diff to <output file>.")
  print("")
  print(" WARNING: All files used here must be in the PNG format!")
end


if not arg[1] or not arg[2] then
  usage()
  os.exit(1)
end

if arg[1] == "show" then
  im = gd.createFromPng(arg[2])
  if not im then    
    print("ERROR: Bad image data.")
    os.exit(1)
  end
  io.write(getMessage(im))
  os.exit(0)
end

if arg[1] == "hide" then
  if not arg[3] then
    usage()
    os.exit(1)
  end
  im = gd.createFromPng(arg[2])
  if not im then
    print("ERROR: Bad image data.")
    os.exit(1)
  end
  print("Type your message and press CTRL+D to finish.")
  msg = io.read("*a")
  oim, l, t = mergeMessage(im, msg)
  if not oim then
    print("ERROR: Image is too small for the message.")
    os.exit(1)
  end
  if not oim:png(arg[3]) then
    print("ERROR: Failed to write output file.")
    os.exit(1)
  end
  print(string.format("DONE: %2.1f%% of the image used to store the message.",
    100.0*l/t))
  os.exit(0)
end

if arg[1] == "diff" then
  if not arg[3] and arg[4] then
    usage()
    os.exit(1)
  end
  oim = compare(arg[2], arg[3])
  if not oim:png(arg[4]) then
    print("ERROR: Failed to write output file.")
    os.exit(1)
  end
  os.exit(0)
end

usage()
os.exit(1)

Other examples

There are some useful examples in the demos directory within the distribution package.

Contact information

Author: Alexandre Erwin Ittner
E-mail: aittner#netuno.com.br (e-mail obfuscated to avoid spam-bots. Please replace the "#" with an "@").
GnuPG/PGP Key: 0x0041A1FB (key fingerprint: 9B49 FCE2 E6B9 D1AD 6101 29AD 4F6D F114 0041 A1FB).
Homepage: http://users.netuno.com.br/aittner/.
Location: Jaraguá do Sul, Santa Catarina, Brazil.


$Id$