Guide

Getting Started

It is important to understand that IM is based in 4 concepts: Image Representation, Image Storage, Image Processing and Image Capture. The following picture illustrates the relation between theses concepts.

IM does not have support for Image Visualization, because we think this is a task for a graphics library like OpenGL, Windows GDI or CD - Canvas Draw.

Image Representation describes the image model and its details. Which color systems are going to be used, which data types, how the data is organized in memory, and how other image characteristics are accessed.

Image Storage describers the file format model and how images are obtained or saved. Image Capture describes the access to a capture device and obtaining an image from it. Image Processing describes the image processing operations.

There are infinite ways to implement these concepts. There is no common definition in the literature, but there is a standard called Programmer's Imaging Kernel System (PIKS) published at the ISO/IEC 12087. PIKS is a very complete and also complex standard, very hard to implement. There are only a few implementations available, and the one that I know is commercial software, Pixel Soft of William Pratt http://www.pixelsoft.com/, also author of several books on the subject.

But we want something easier to implement and understand. The free available libraries that we found where sometimes close to what we want, sometimes very far. So we developed our own.

The documentation contains Overview, Guide, Samples and Reference sections for each one of the IM concepts.

The Guide is where you are going to find the explanation about the concepts and decisions made during the library design. It is the best place to understand how things works.

The Reference contains pure essential information for function and structure usage. But there is no information on how to put the functions to work together. It is generated automatically from the source code using Doxygen, this means also that the include files (*.h) are very well commented.

Building Applications

Inside you code you should at least include the <im.h> header and link with the "im.lib/libim.a/libim.so" library. This library contains all the Image Representation functions and all the Image Storage functions (with the exception of the external formats: AVI, JP2 and WMV).

Each external format or processing usually needs a <im_xx.h> file and a "im_xx.lib/libim_xx.a/libim_xx.so" file.

Even if your application is only in C, you must link with a C++ capable linker. Using Tecmake set "LINKER := g++" in your "config.mak" when compiling with gcc (UNIX and Windows).

The download files list includes the Tecgraf/PUC-Rio Library Download Tips document, with a description of all the available binaries.

Building the Library

In the Downloads you will be able to find pre-compiled binaries for many platforms, all those binaries were built using Tecmake. Tecmake is a command line multi compiler build tool based on GNU make, available at http://www.tecgraf.puc-rio.br/tecmake. Tecmake is used by all the Tecgraf libraries and many applications.

You do not need to install Tecmake, scripts for Posix and Windows systems are already included in the source code package. Just type "make" in the command line on the main folder and all libraries and executables will be build.

In Linux, check the "Building Lua, IM, CD and IUP in Linux" guide.

In Windows, check the "Building Lua, IM, CD and IUP in Window" guide.

If you decide to install Tecmake, the Tecmake configuration files (*.mak) are available at the "src" folder, and are very easy to understand. In the main folder, and in each source folder, there are files named make_uname.bat that build the libraries using Tecmake. To build for Windows using Visual C 9.0 (2008) for example, just execute "make_uname vc9" in the iup main folder, or for the DLLs type "make_uname dll9". The Visual Studio workspaces with the respective projects available in the source package is for debugging purposes only.

Make sure you have all the dependencies for the library you want installed, see the documentation bellow.

If you are going to build all the libraries, the makefiles and projects expect the following directory tree:

\mylibs\
        im\
        lua5.1\

To control that location set the TECTOOLS_HOME environment variable to the folder were the Lua libraries are installed.

Libraries Dependencies

im -> libjpeg (included)
   -> libpng  (included)
   -> libtiff (included)
   -> zlib
   -> liblzf  (included)
   -> libexif (included)
im_jp2 -> im
       -> libJasper (included)
im_avi -> im
       -> vfw32 (system - Windows)
im_wmv -> im
       -> wmvcore (system - Windows)
im_ecw -> im
       -> NCSEcw (system)
im_capture -> strmiids (system - Windows)
im_process -> im
im_fftw -> im
        -> fftw (included)
imlua51 -> im
        -> lua5.1
imlua_capture51 -> imlua51
                -> im_capture
imlua_fftw51 -> imlua51
             -> im_fftw
imlua_process51 -> imlua51
                -> im_process

As a general rule (excluding system dependencies and included third party libraries): IM has NO external dependencies, and IMLua depends on Lua.

The Lua bindings for IUP, CD and IM (Makefiles and Pre-compiled binaries) depend on the LuaBinaries distribution. So if you are going to build from source, then use the LuaBinaries source package also, not the Lua.org original source package. If you like to use another location for the Lua files define LUA_SUFFIX, LUA_INC, LUA_LIB and LUA_BIN before using Tecmake.

CD Compatibility

IM version 2 was designed to perfectly work with the CD - Canvas Draw toolkit. Version 3 has many more options and only for a subset of the images called Bitmaps can be used with the CD functions. Theses images have data type IM_BYTE, and color mode IM_RGB, IM_GRAY, IM_MAP or IM_BINARY. They can not have the flags IM_TOPDOWN and IM_PACKED. But it can have the flag IM_ALPHA for IM_RGB images.

You can convert an image to a bitmap version of it using the function imConvertToBitmap, see Image Representation / Conversion.

Function cdCanvasGetImageRGB captures an image from the active canvas. Functions cdCanvasPutImageRect* draw a client image on the active canvas. These functions allow reducing or increasing the image when drawing.

For applications in systems with only 256 colors available, we recommend the use of function cdCanvasPalette before drawing the image, to improve its quality.

When using the imImage structure the macro imcdCanvasPutImage can be used. It is defined as:

#define imcdCanvasPutImage(_canvas, _image, _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax)     \
  {                                                                         \
    if (_image->color_space == IM_RGB)                                      \
    {                                                                       \
      if (image->has_alpha)                                                 \
        cdCanvasPutImageRectRGBA(_canvas, _image->width, _image->height,    \
                          (unsigned char*)_image->data[0],                  \
                          (unsigned char*)_image->data[1],                  \
                          (unsigned char*)_image->data[2],                  \
                          (unsigned char*)_image->data[3],                  \
                          _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax);      \
      else                                                                  \
        cdCanvasPutImageRectRGB(_canvas, _image->width, _image->height,     \
                          (unsigned char*)_image->data[0],                  \
                          (unsigned char*)_image->data[1],                  \
                          (unsigned char*)_image->data[2],                  \
                          _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax);      \
    }                                                                       \
    else                                                                    \
      cdCanvasPutImageRectMap(_canvas, _image->width, _image->height,       \
                        (unsigned char*)_image->data[0], _image->palette,   \
                        _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax);        \
  }

CD Library is the Tecgraf 2D graphics library available at http://www.tecgraf.puc-rio.br/cd.

OpenGL Compatibility

The function glDrawPixels accepts several data types and color modes. Here are the format and type mapping for OpenGL usage:

           IM             <->  OpenGL
        color_mode             format
IM_RGB|IM_ALPHA|IM_PACKED  = GL_RGBA               
IM_RGB|IM_PACKED           = GL_RGB
IM_GRAY                    = GL_LUMINANCE
IM_GRAY|IM_ALPHA|IM_PACKED = GL_LUMINANCE_ALPHA
        data_type              type
IM_BYTE                    = GL_UNSIGNED_BYTE
IM_BINARY                  = GL_BITMAP
IM_USHORT                  = GL_UNSIGNED_SHORT
IM_INT                     = GL_INT
IM_FLOAT                   = GL_FLOAT

There is no mapping for non IM_PACKED images so if you use unpacked planes (ex: you use the imImage structure) then you have to convert one data into another, the function imConvertPacking does this, so you just have to keep an extra buffer for the display image and call this function only when your original image has changed. See Image Representation / Conversion. For example:

imConvertPacking(image->data[0], gl_data, image->width, image->height, image->depth, image->data_type, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* data alignment must be 1 */

glDrawPixels(image->width, image->height, GL_RGB, GL_UNSIGNED_BYTE, gl_data);

When loading color image data you can use the function imConvertMapToRGB to convert in-place IM_MAP image data into IM_RGB after loading it from file. For example:

if (imColorSpace(color_mode) == IM_MAP)
{
  long palette[256];
  int palette_count, packed = 1; /* OpenGL uses packed RGB */
  imFileGetPalette(ifile, palette, &palette_count);
  imConvertMapToRGB(gl_data, width*height, depth, packed, palette, palette_count);
}

If you are using the imImage structure then you can instead use the function imImageGetOpenGLData.

If you just want to save your OpenGL buffer then you can use:

glPixelStorei(GL_PACK_ALIGNMENT, 1); /* data alignment must be 1 */
glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, gl_data);

ifile = imFileNew(filename, format, &error);
error = imFileWriteImageInfo(ifile, width, height, IM_RGB|IM_PACKED, IM_BYTE);
error = imFileWriteImageData(ifile, gl_data);
imFileClose(ifile); 

And when using the imImage structure then you can instead use the function imImageCreateFromOpenGLData. For instance:

glPixelStorei(GL_PACK_ALIGNMENT, 1); /* data alignment must be 1 */
glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, gl_data);

imImage* image = imImageCreateFromOpenGLData(width, height, GL_RGB, gl_data); 
error = imFileImageSave(filename, format, image);

You can also do this inside a loop to create an animation. 

IM 2.x Compatibility

In version 3.0 the library was completely rewritten. And we changed the main API to allow more powerful features. But the old API is still available for backward compatibility. Version 3 is also binary compatible with version 2.

The only change that must be updated in old applications if they where recompiled is some error code definitions. If you use them in a case there will cause a compiler error because IM_ERR_READ and IM_ERR_WRITE are now defined as IM_ERR_ACCESS both.

Migrating OLD Code

The old API is very inefficient because the file is opened and close three times, for: imFileInfo, imImageInfo and imLoadRGB/imLoadMap. There is no room for attributes, so we use the callbacks. And we can not load sequences of images. For these reasons we change the API.

If you would like to migrate your code using the old API the most important thing to change is the memory allocation. For RGB images instead of allocating 3 separate pointers you should allocate only one pointer with room for all three planes. If you still want to keep the three pointers, just do green = red + width*height and blue = red + 2*width*height.

Also you should change your callbacks usage for attributes access using imFileGetAttribute and imFileSetAttribute. IM_RESOLUTION_CB is replaced by the attributes "XResolution", "YResolution", "ResolutionUnit". IM_GIF_TRANSPARENT_COLOR_CB is replaced by "TransparencyIndex" and IM_TIF_IMAGE_DESCRIPTION_CB by "Description".

Except IM_COUNTER_CB that is not an attribute, still works with a callback, but now we implement a counter system for all the library including loading, saving and processing. The user just use the imCounterSetCallback (like before) to register it counter callback, now there are a few more parameters and a user data pointer. See Utilities / Counter.

The function calls to imImageInfo and imLoadRGB/imLoadMap will be replaced by a sequence of function calls to imFileOpen/imFileNewimFileReadImageInfo/imFileWriteImageInfo, imFileReadImageData/imFileWriteImageData and imFileClose. See Image Storage.

Names Convention

To improve the readability of the code we use a very simple naming convention:

C x C++ Usage

The library main API is in C. We adopt this because of the many C programmers out there. Some of the API is also available in C++ for those addicted to classes.

Internally C++ is used to implement the format driver base architecture. A virtual base class that every drivers inherits from. This made a lot of things easier to the driver development. But we keep it simple, no multiple inheritance, no exception handling, no complicated classes.

But because we need several data types C++ templates were inevitable used (since we do not like long macros everywhere). But they are used only for processing functions, not classes.