CD - Canvas Draw

Lua Binding

Overview

CDLua was developed to make all functionalities of the CD library available to Lua programmers. To use the CDLua bindings, your executable must be linked with the CDLua library, and you must call the initialization function cdlua_open declared in the header file cdlua.h, as seen in the example below:

in Lua 3

in Lua5

#include <lua.h>
#include <lualib.h>

#include <cdlua.h>
void main(void)
{
  lua_open();
  
  iolib_open();
  strlib_open();
  mathlib_open();

  cdlua_open();

  lua_dofile("myprog.lua");
  
  cdlua_close();
  lua_close();
}
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <cdlua.h>
void main(void)
{
  lua_State *L = lua_open();

  luaopen_string(L);
  luaopen_math(L);
  luaopen_io(L);  

  cdlua_open(L);

  lua_dofile("myprog.lua");
  
  cdlua_close(L);
  lua_close(L);
}

The cdlua_open() function registers all CD functions and constants your Lua program will need. The use of the CDLua functions in Lua is generally identical to their equivalents in C. Nevertheless, there are several exceptions due to differences between the two languages. Notice that, as opposed to C, in which the flags are combined with the bitwise operator OR, in Lua the flags are added arithmetically.

As in C, it is important to make sure there is a currently active canvas before calling any CDLua function. Otherwise, the Lua program will be aborted with an error message. Canvases are created and activated as in C:

cnv = cd.CreateCanvas(cd.IUP, "test.ps")
if cnv == nil then
  -- deal with error
  ...
else
  cd.Activate(cnv)
end

Function Names and Definitions

In Lua, because of the name space "cd" all the functions and definitions have their names prefix changed. The general rule is quite simple:

cdXxx  -> cd.Xxx
wdXxx  -> cd.wXxx
CD_XXX -> cd.XXX

In Lua 3, because of backward compatibility the old names are also available.

Data Types

Lua native data types were not enough for the CDLua bind, because CD deals with a series of data types other than strings and numbers. Therefore, to provide the eficiency required, usertags or metatables were used to implement such data types. They are:

"cdlua_color_tag" (color_tag): type used by functions cdEncodeColor, cdDecodeColor, cdPixel, cdForeground and cdBackground. Except in Lua 5 where the color_tag is a light user data.
"cdlua_imageex_tag" (imageex_tag): type used by functions cdCreateImageEx, cdKillImageEx, cdGetImageEx, cdPutImage and cdPutImageEx.
"cdlua_image_tag" (image_tag): type used by functions cdCreateImage, cdKillImage, cdGetImage, cdPutImage and cdPutImage.
"cdlua_imagergb_tag" (imagergb_tag): type used by functions cdCreateImageRGB, cdKillImageRGB, cdGetImageRGB and cdPutImageRGB.
"cdlua_imagergba_tag" (imagergba_tag): type used by functions cdCreateImageRGBA, cdKillImageRGBA and cdPutImageRGBA.
"cdlua_imagemap_tag" (imagemap_tag): type used by functions cdCreateImageMap, cdKillImageMap and cdPutImageMap.
"cdlua_palette_tag" (palette_tag): type used by functions cdCreatePalette, cdKillPalette, cdPalette and cdPutImageMap.
"cdlua_pattern_tag" (pattern_tag): type used by functions cdCreatePattern, cdKillPattern and cdPattern.
"cdlua_stipple_tag" (stipple_tag): type used by functions cdCreateStipple, cdKillStipple and cdStipple.
"
cdlua_channel_tag" (channel_tag): type used by channel image access methods. Internal use only.
"cdlua_canvas_tag" (canvas_tag): type used by cdCreateCanvas, cdActivate, cdKillCanvas, cdGetContext and cdContextCaps.
"cdlua_state_tag" (state_tag): type used bycdSaveState and cdRestoreState.

All the usertags are available to the C programmer in Lua 3 global variables or Lua 5 metatables with the given names. The respective structures are defined in the cdluapvt.h header.

The structure cdContext is stored as a number, and did not need a usertag.

New Functions

New functions (without equivalents in C) were implemented to create and to destroy objects of the new data types. Functions were developed to create and remove images, pattern, stipple and palette.

In case of error (for example, lack of memory), the creation functions return nil. The user must verify its return value. See the example below:

pattern = cd.CreatePattern(16, 16)
if pattern == nil then
  ...
end

Modified Functions

Some functions were modified to receive parameters of the types imagergb_tag, imagergba_tag, imagemap_tag, palette_tag, stipple_tag and pattern_tag. These objects already have their dimensions stored internally and, therefore, the user does not need to pass them as parameters.

The functions which receive values by referencing to C were also modified in Lua. Generally, the values of parameters that would have their values modified are now returned by the function in the same order.

The functions still have the same functionality, but they are now used differently:

w, h = cd.GetCanvasSize()
red, green, blue = cd.DecodeColor(CD_DARK_MAGENTA)
x, y = cd.Canvas2Raster(x, y)

Garbage Collection

All the objects are garbage collected by the Lua garbage collected, with the execption of the Canvas. This means that all the cd.Kill* functions are optional, with the exception of the cd.KillCanvas.

Exchanging Values between C and Lua

Because of some applications that interchange the use of CD canvases in Lua and C, we build a simple C function to retreive the pointer of a CD canvas created in Lua: cdlua_getcanvas. It is declared in the cdlua.h header. The canvas to be retreived must be in the Lua stack before calling this function. Usually you will do a lua_pushobject(lua_getglobal("mycanvas")) call before it.

Error Checking

Rigorous parameter checking is performed by CDLua functions before passing the parameters to CD. When an error is considered fatal, the library interrupts the Lua program and shows an explanatory error message. Errors in the number and types of parameters, and inconsistency in the values of parameters are considered as fatal errors. In general, fatal errors are those that require a change in the Lua code and would cause an equivalent C program to crash.

All fatal errors result in a call to lua_error with a message with format "function: message", where function is the name of the function that detected the fatal error and message is a message that identifies the error. Some of the most important errors are seen in the examples below:

"cdlua: there is no active canvas!"
"cdActivate: attempt to activate a killed canvas!"
"cdCreateCanvas: unknown driver!"
"cdKillStipple: attempt to kill a killed stipple!" 
"cdCreateCanvas CD_IUP: data should be an iuplua canvas object!"
"cdCreateCanvas CD_IMAGE: data is a NIL image!"
"cdCreateCanvas CD_PRINTER: data should be of type string!"
"cdPlay: CD_SIZECB: invalid return value!"
"cdCreateCanvas CD_SIMULATE: too many parameters!"
"cdRegisterCallback: unknown callback!"
"cdPlay: driver does not implement the play function or unknown driver!"
"cdKillCanvas: attempt to kill a NIL canvas!"
"cdEncodeColor: color components values should be in range [0, 255]!"
"cdCreateStipple: stipple dimensions should be positive integers!"

The fallbacks used to modify and to check the values of types imagergb_tag, imagergba_tag, imagemap_tag, palette_tag, pattern_tag and stipple_tag also perform error checking and can detect fatal errors. The methods check for vector bounds, and for parameter types and values. The messages have the format "type 'fallback': message", as seen below:

"pattern_tag "settable": index should be a number!"
"imagemap_tag "gettable": index out of bounds!"
"stipple_tag "settable": value should belong to {0, 1}!"
"pattern_tag "settable": value should be of type color_tag!"

Integration with IMLua

CDLua is fully integrated with IMLua. Yet, both libraries are completely independent. Whenever both libraries are initialized (the order is not important), each library can detect the presence of the other and enable the interaction. Being independent, each library provides its own set of functions to create, access, modify and destroy the new data types. Actually, they share the same tag values for the data types common to CD and IM, so that objects created by CDLua are indistinguishable from objects created by IMLua. The example below shows a perfectly valid CDLua/IMLua code:

...
w, h = imImageInfo(filename)
image = cdCreateImageRGB(w, h)
imLoadRGB(filename, image)
cdPutImageRGB(image, x, y, w, h) 
imKillImageRGB(image)