TOC PREV NEXT INDEX

The Data Visualization Kit


A
Adding your own image readers and writers


This appendix outlines how to write your own image readers and writers to supplement the image formats already supported by the DVread_image/ Read_Image and DVwrite_image/ Write_Image objects.

This appendix discusses:

A.1 Overview

AVS/Express provides Application Programming Interfaces (APIs) that allow you to more easily write your own image readers and writers for AVS/Express.

Image reader API

The image reader API provides five function calls:

Image writer API

The image writer API provides ten calls:

A.2 Implementing an image reader

To add an image reader you write a library consisting (minimally) of this set of functions and "register" the library in the modules/rd_image.c source code. The necessary steps are outlined in the following procedures:

1. Edit v/modules.v and add the name of your reader to the UIradioBoxLabel labels list. Its position in the list must correspond to that in FUNCread_map array in modules/rd_image.c since the integer value returned for the type will correspond to this order. See later in these procedures for further information.
2. Edit modules/image.h to add a #define DV_IMAGE_FORMAT_xxx entry for the new file format. Add function prototypes for the interface functions to the new image reader library, also in image.h. Note that the function arguments must correspond to the library API, that is, be identical to others in image.h. The API function names can be any (unique) name you choose.
3. Edit modules/rd_image.c to add the new format to the FUNCread_map list. This array is a list of entries of the form:
<DV_IMAGE_FORMAT_xxx>, <format info>

This is used to map the UI type value to an independent file format definition. Ensure your reader's position in the list correspond with that in the UIradiobox list.

Add an xxx_info[] static char array of library and function names, and a funcs_t static struct for the new reader library. The function names, of course, correspond to those in modules/image.h. The library name in the xxx_info array can be anything you choose but must be unique. Ensure that the info and funcs lists are correctly added as the <format info> in the FUNCread_map array.

The xxx_info[] array is used if the reader library is to be dynamically loaded, the funcs_t struct is used if the reader library is linked into the AVS/Express application (either statically or as a shared library). For further explanation of this subject, see below.

4. Also in modules/rd_image.c, add a DV_IMAGE_FORMAT_xxx case to the format switch in DVread_image_update().

Add an else clause for the new filetype in FUNCget_image_filetype(). This is the function that determines the format from the file itself.

Add a DV_FILETYPE_xxx case to the type switch in FUNCget_image_filetype_name(). This function returns the ASCII name of a filetype given its integer value.

5. Write the library functions. These will likely consist of the set of API interface functions, plus some lower-level reader functions that access header information, colormap data (if present), and the raw image data from the file. These functions will also do any data decompression required.

You may look at the modules/image/libavsx library functions as an example of how to write the interface functions. This is a very simple example, but it does illustrate, in particular, how the API defines a void struct to reference data between the library and the caller. This is the mechanism by which the generic FUNCread_image() function in modules/rd_image.c could be written: the caller has no knowledge of the data structure internals being passed to and from the library.

6. Decide whether you want to build the reader library into the AVS/Express executable (either statically or dynamically) at link time, or dynamically load the library at run time. For most platforms, loading the library dynamically at run time is the default (see the appropriate include/<machine>/machinc.mk file to find out if this is the case for your platform).

Loading the library dynamically at run time has the benefit of occupying no physical memory when you run the application until a call is made into the library. This is particular advantageous if the library is very large and never referenced. There are disadvantages, however:

There is a small overhead of loading the library the first time it is referenced (compared with static linking an archive file).
It is impossible to specify the path to the library at link time since its location can be anywhere and the application can be started from any location. This problem is common to all shared libraries and is typically resolved by setting an environment variable, for example LD_LIBRARY_PATH. See the System Prerequisites documentation for specific details about how to set up your system to handle shared libraries.
It can be difficult to debug a dynamically loaded library during development. A common strategy is to statically link the library during development then switch to dynamic loading when the library is debugged.

To link the reader libraries into the executable, the NO_DL_LOAD compiler flag must be defined when compiling modules/rd_image.c. You can do this in two ways:

Specify -DNO_DL_LOAD in the modules makefile (Makefile on UNIX systems; nt.mak on the PC)
Specify -DNO_DL_LOAD in the "G" environment variable (see the include/<machine>/machinc.mk file) and combined with the -e make flag when compiling. This second method is particularly useful for temporarily setting the flag and compiler debug options when debugging.
Note: Regardless of the method it will be necessary to edit the express.mk makefile to add the list of libraries normally referenced at run time to the express link line. To do this, search for "-lmods" in that file and add the list right after that library. You can find this list in v/templ.v. Search this file for "NO_DL_LOAD" - the list of libraries is right after that reference. Add your new library to this list.

To permanently bind the dynamic libraries at link time the best solution is to edit the include/<machine>/machinc.mk file and add NO_DL_LOAD to the list of CONFIGFLAGS. This will cause NO_DL_LOAD to be defined in the compiler flags list, and it will automatically add all the normally dynamically loaded libraries to the express link line. Note you will need to add your library to the v/templ.v NO_DL_LOAD library list for inclusion in express.mk.

There is currently no easy way to selectively add dynamic libraries to the list for inclusion at link time and reference others at run time, although this might be done by editing v/templ.v, the machinc.mk and rd_image.c files.

A.3 Implementing an image writer

To add an image writer you write a library consisting (minimally) of the set of API functions and "register" the library in the modules/wr_image.c source code. The necessary steps are outlined in the following procedures:

1. Edit v/modules.v and add a new UIoption to the format list following the format_label UIlabel. Add this option to the format_db UIradioBox cmdList. It's position in the list must correspond to the that in FUNCwrite_map array in modules/wr_image.c since the integer value returned for the type will correspond to this order. See later in these procedures for further information. Update the active fields in the UIoptions for the new writer. This enables or disables the various radiobox buttons and should be set to be appropriate for your new writer. Add the new value in the correct place to the switched list of values that are set according to the selectedItem in the format_rb. This looks complicated but is actually straightforward once you understand the mechanism. This is the mechanism to use if you wish to add new parameters to the write_image module.
2. Edit modules/image.h and add a #define DV_IMAGE_FORMAT_xxx entry for the new file format. Add function prototypes for the interface functions to the new image writer library, also in image.h. Note that the function arguments must correspond to the library API, that is, be identical to others in image.h. The API function names can be any (unique) name you choose.
3. Edit modules/wr_image.c and add the new format to the FUNCwrie_map list. This array is a list of entries of the form:
<DV_IMAGE_FORMAT_xxx>, <format info>

This is used to map the UI type value to an independent file format definition. Ensure your writer's position in the list correspond with that in the UIradiobox list.

Add an xxx_info[] static char array of library and function names, and a funcs_t static struct for the new library. The function names, of course, correspond to those in modules/image.h. The library name in the xxx_info array can be anything you choose but must be unique. Ensure that the info and funcs lists are correctly added as the <format info> in the FUNCwrite_map array.

The xxx_info[] array is used if the reader library is to be dynamically loaded, the funcs_t struct is used if the reader library is linked into the AVS/Express application (either statically or as a shared library). For further explanation of this subject, see below.

4. Also in modules/wr_image.c, add a DV_IMAGE_FORMAT_xxx case to the format switch in DVwrite_image_update().
5. Write the library functions. These will likely consist of the set of API interface functions, plus some lower-level writer functions that write header information, colormap data (if present) and the encoded image data from the AVS field. These functions will also do any data compression required.

You may look at the modules/image/libavsx library functions as an example of how to write the interface functions. This is a very simple example, but it does illustrate, in particular, how the API defines a void struct to reference data between the library and the caller. This is the mechanism by which the generic FUNCwrite_image() function in modules/wr_image.c could be written: the caller has no knowledge of the data structure internals being passed to and from the library.

6. Decide whether you want to build the writer library into the AVS/Express executable (either statically or dynamically) at link time, or dynamically load the library at run time. For most platforms, loading the library dynamically at run time is the default (see the appropriate include/<machine>/machinc.mk file to find out if this is the case for your platform).

Loading the library dynamically at run time has the benefit of occupying no physical memory when you run the application until a call is made into the library. This is particular advantageous if the library is very large and never referenced. There are disadvantages, however:

There is a small overhead of loading the library the first time it is referenced (compared with static linking an archive file).
It is impossible to specify The path to the library at link time since its location can be anywhere and the application can be started from any location. This problem is common to all shared libraries and is typically resolved by setting an environment variable, for example LD_LIBRARY_PATH. See the System Prerequisites documentation for specific details about the impact of shared libraries.
It can be difficult to debug a dynamically loaded library during development. A common strategy is to statically link the library during development then switch to dynamic loading when the library is debugged.

To link the reader libraries into the executable, the NO_DL_LOAD compiler flag must be defined when compiling modules/wr_image.c. This can be achieved in two ways:

Specify -DNO_DL_LOAD in the modules makefile (Makefile on UNIX systems; nt.mak on the PC)
Specify -DNO_DL_LOAD in the "G" environment variable (see the include/<machine>/machinc.mk file) and combined with the -e make flag when compiling. This second method is particularly useful for temporarily setting the flag and compiler debug options when debugging.
Note: regardless of the method it will be necessary to edit the express.mk makefile and add the list of libraries normally referenced at run time to the express link line. To do this search for "-lmods" in that file and add the list right after that library. The list can be found in v/templ.v. Search this file for "NO_DL_LOAD" - the list of libraries is right after that reference. Add your new library to this list.

To permanently bind the dynamic libraries at link time the best solution is to edit the include/<machine>/machinc.mk file and add NO_DL_LOAD to the list of CONFIGFLAGS. This will cause NO_DL_LOAD to be defined in the compiler flags list, and it will automatically add all the normally dynamically loaded libraries to the express link line. Note you will need to add your library to the v/templ.v NO_DL_LOAD library list for inclusion in express.mk.

There is currently no easy way to selectively add dynamic libraries to the list for inclusion at link time and reference others at run time, although this might be done by editing v/templ.v, the machinc.mk and wr_image.c files.


TOC PREV NEXT INDEX

Copyright © 2001 Advanced Visual Systems Inc.
All rights reserved.