After spending too much time looking around the legacy code, and thinking about the "good" way to upgrade it to ANSI C, I decided to try to rewrite it, gradually. So, I start with the images. The basic ideas are:
- implement only the basic things, add extra features later if we really need them
- document and test everything
- maintain a clean coding style, inspired by this standard
u8image
This matches the original cimage type,
reloaded. uint8 is a typedef for unsigned char; we also have
uint16, uint32 (no uint64, no long long int in ANSI C),
float32 and float64 for the other structures.
This structure is defined in [[mw4f lib/src/u8image.h]], with the implementation details in [[mw4f lib/src/u8image.c]] :
/**
* 8-bit unsigned integer gray level image
*/
typedef struct s_u8image
{
uint16 ncol; /**< number of columns (dx) */
uint16 nrow; /**< number of rows (dy) */
uint8 * gray; /**< gray level plane */
} mw_u8image;
/* create an image */
mw_u8image * mw_new_u8image(uint16, uint16);
/* delete an image */
void mw_del_u8image(mw_u8image *);
/* copy an array an image */
mw_u8image * mw_setdata_u8image(mw_u8image *, const uint8 *);
/* copy an image into an existing one */
mw_u8image * mw_copy_u8image(mw_u8image *, mw_u8image *);
/* copy an image into a new one */
mw_u8image * mw_clone_u8image(mw_u8image *);
/* get one value of an image */
int16 mw_getdot_u8image(mw_u8image *, uint16, uint16);
/* set one value of an image */
int16 mw_setdot_u8image(mw_u8image *, uint16, uint16, uint8);
/* fill an image */
uint8 * mw_fill_u8image(mw_u8image *, uint8);
/* write a text representation of an image to a file */
int32 mw_fwrite_u8image(FILE *, mw_u8image *);
/* read a text representation of an image from a file */
mw_u8image * mw_fread_u8image(FILE *);
So, what is different?
the structure
ncolandncolare unsigned; it makes sense for indicesncolandnroware limited to 2^16; this means 2^32 image pixels, too much...- no more
allocsize; the number of pixels is easily computable fromncolandnrow, and the real allocation size shouldn't be exposed (sensible, and might be arch-dependant) - no more
scale; let's see later if we need it in the structure - no more
nameorcomment; same reasons - no more
{first|last}{col|row}; same reasons - no more
prevornext; I feel this information should only be handled by the movie structure mw_u8imageis the type of the structure, not a pointer to the structure; so, we have to explicitly mention the pointer syntax, and I think improves the code readability
the functions
mw_new_u8imageallocates the structure and the array; there is no moremw_change_u8image; it seems that the previous "image resizing without realer" feature was not used a lot, and this kind of thing is a candidate for memory leaks; so, from now, we create an image, we delete an image, but we don't resign it on-the fly; in some cases, it may imply a performance loss, but the main performance focus is on the algorithmsmw_{setdata|copy|clone}_u8imageare handy shortcuts to duplicate some datamw_{getdot|setdot|fill}_u8imagemay not be used a lot; but it's a good way to start manipulating the imagesmw_{fwrite|fread}_u8imagewrite or read a text representation of the images; I think it may be the preferred way to dump some data, for personal use, or maybe when there is no natural format (think about float images); text representation make it for perfect portability, readability, and make editing easy; for the moment I chose the JSON format for its flexibility and the availability of writing/parsing libraries; text format might be bigger and slower to process than a binary format, but we can gzip it, and... once again, the performance is in the algorithms, not in the i/o.
u16image, f32image, ...
Same, with another data type. See [[mw4f lib/src/u16image.h]]/[[mw4f lib/src/u16image.c]] and [[mw4f lib/src/f32image.h]]/[[mw4f lib/src/f32image.c]].
notes
All the new code is documented a la doxygen and tested with:
- static linting with
splint +posixlib +weak -ansi89limits - separate compilation with
gcc -Wall -I. -pedantic -Werror -Wc++-compat -Wextra -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs - unit tests with CUnit
In the future, these gray-level structures might be merged with the color images.
I also think about a "package", with all the basic operations one may want to perform on an image:
addan image or a scalar to an imagesuban image or a scalar from an imagemulan image by an image or a scalardivan image by an image or a scalarmaxof an imageminof an imagemeanof an imagefmeanof an imageANDan image and an image or a scalarORan image and an image or a scalarXORan image and an image or a scalarANDan image and an image or a scalar
By the way, we stick to ANSI C, but overloading and default parameters
would be really nice there; it's possible to implement sort of
overloading in C with unions, but at the price of a code difficult
to write, read, use and maintain. Maybe a C++ overlay later?