/* * The Npic library * * Copyright (C) 2003 Edouard Thiel * * This library is free software under the terms of the * GNU Lesser General Public License (LGPL) version 2.1. */ /* * files_vol.c - 07/10/2008 * * VOL - volume format from David Coeurjolly and Alexis Guillaume * * see http://www.cb.uu.se/~tc18/code_data_set/Code/Libvol/ */ #include #define MAXBUF 65536 #define FBUF_INT8 4096 #define FBUF_INT32 1024 /* From Libvol */ #define MAX_NUMLINES 64 #define MAX_LINELEN 128 /*--------------------- P U B L I C - I N T E R F A C E ----------------------*/ /* * Save Npic_image image of type NPIC_IMAGE_3C or 3L in a file in VOL format. * If comp != NPIC_COMPRESS_NONE, the file is directly compressed using * the appropriate command (see files_hints.h for available formats). * Do nothing if image is not ok. * * Return NPIC_SUCCESS, else error code. Verbose. * * USAGE : * Npic_image *np; int err; * ... * err = NpicWriteVOL (&np, "example.vol" , NPIC_COMPRESS_NONE); * or err = NpicWriteVOL (&np, "example.vol.gz", NPIC_COMPRESS_GZ); * if (err < 0) return err; * .... * NpicDestroyImage (np); */ int NpicWriteVOL (Npic_image *np, const char *filename, Npic_file_compress comp) { Npic_file_gz fgz; if (NpicImageIsOK (np, __func__) != NPIC_SUCCESS) return NPIC_ERR_NOT_OK; NpicWriteGZ_Open (&fgz, filename, __func__, 0, comp); if (fgz.res == NPIC_SUCCESS) fgz.res = NpicVOLWriteFile (np, fgz.f2, filename, __func__); NpicWriteGZ_Close (&fgz); return fgz.res; } /* * Read image file in VOL format and create Npic_image image of type * NPIC_IMAGE_3C or 3L. * If comp != NPIC_COMPRESS_NONE, the file is uncompressed in memory using * the appropriate command (but stay compressed on disk). * Return image on success, else return NULL. Verbose. * * USAGE : * Npic_image *np; * np = NpicReadVOL ("example.vol" , NPIC_COMPRESS_NONE); * or np = NpicReadVOL ("example.vol.gz", NPIC_COMPRESS_GZ); * if (np == NULL) return; * .... * NpicDestroyImage (np); */ Npic_image *NpicReadVOL (const char *filename, Npic_file_compress comp) { Npic_image *np = NULL; Npic_file_gz fgz; NpicReadGZ_Open (&fgz, filename, __func__, 0, comp); if (fgz.res == NPIC_SUCCESS) np = NpicVOLReadFile (fgz.f2, filename, __func__); NpicReadGZ_Close (&fgz); return np; } /* * Print infos of a file in VOL format * * Return NPIC_SUCCESS, else error code. Verbose. */ int NpicInfoVOL (const char *filename, Npic_file_compress comp) { Npic_file_gz fgz; Npic_vol_info info; NpicReadGZ_Open (&fgz, filename, __func__, 0, comp); if (fgz.res == NPIC_SUCCESS) { fgz.res = NPicVOLReadInfo (fgz.f2, &info); if (fgz.res == NPIC_SUCCESS) fgz.res = NpicVOLPrintInfo (filename, &info); NpicError (__func__, fgz.res, ": file \"%s\"", filename); NpicFreeProps (&info.props); } NpicReadGZ_Close (&fgz); return fgz.res; } /*-------------------- P R I V A T E - F U N C T I O N S ---------------------*/ /* * Save Npic_image image of type NPIC_IMAGE_3C or 3L in a file in VOL format. * The file is already fopen. * Return NPIC_SUCCESS, else error code. Verbose. */ int NpicVOLWriteFile (Npic_image *np, FILE *f1, const char *filename, const char *funcname) { int i, k, n; char *key, line[128]; if (NpicImageIsOK (np, funcname) != NPIC_SUCCESS) return NPIC_ERR_NOT_OK; if (np->type != NPIC_IMAGE_3C && np->type != NPIC_IMAGE_3L) return NpicError (funcname, NPIC_ERR_UNEX_NPIC, ""); /* Mandatory part, not stored as properties in np */ fprintf (f1, "X: %d\n", np->gen.xmax); fprintf (f1, "Y: %d\n", np->gen.ymax); fprintf (f1, "Z: %d\n", np->gen.zmax); switch (np->type) { case NPIC_IMAGE_3C : fprintf (f1, "Voxel-Size: 1\n"); fprintf (f1, "Voxel-Endian: %s\n", NpicVolEndianC()); break; case NPIC_IMAGE_3L : fprintf (f1, "Lvoxel-Size: 4\n"); fprintf (f1, "Lvoxel-Endian: %s\n", NpicVolEndianL()); break; } fprintf (f1, "Int-Endian: %s\n", NpicVolEndianL()); fprintf (f1, "Alpha-Color: %s\n", NpicImageGetPropD (np, "Alpha-Color", "0")); fprintf (f1, "Version: 2\n"); /* Other properties, stored as properties in np */ n = 8; /* Already written */ for (i = 0; i < np->gen.props.nb; i++) { key = np->gen.props.list[i].key; /* Check if prop was already written */ if (strcmp (key, "X") == 0 || strcmp (key, "Y") == 0 || strcmp (key, "Z") == 0 || strcmp (key, "Voxel-Size") == 0 || strcmp (key, "Lvoxel-Size") == 0 || strcmp (key, "Alpha-Color") == 0 || strcmp (key, "Int-Endian") == 0 || strcmp (key, "Voxel-Endian") == 0 || strcmp (key, "Lvoxel-Endian") == 0 || strcmp (key, "Version") == 0 ) continue; /* The number of properties are limited to MAX_NUMLINES ; the next are ignored by Libvol */ if (n++ == MAX_NUMLINES) NpicError (funcname, NPIC_ERROR, ": number of properties exceeds %d, the lasts will be ignored", MAX_NUMLINES); /* Limit line length to MAX_LINELEN */ k = snprintf (line, MAX_LINELEN, "%s: %s", key, np->gen.props.list[i].val ); if (k < 0 || k >= MAX_LINELEN) { NpicError (funcname, NPIC_ERROR, " in property \"%s\", length exceeds %d, truncated.", key, MAX_LINELEN ); line[MAX_LINELEN-1] = 0; } fprintf (f1, "%s\n", line); } /* End of header */ fprintf (f1, ".\n"); /* Finally write raw binary image */ return NpicWriteRAW (np, f1, 0); } /* * Read image file in VOL format and create Npic_image image of type * NPIC_IMAGE_3C or 3L. The file is already fopen. * Return image on success, else return NULL. Verbose. */ Npic_image *NpicVOLReadFile (FILE *f1, const char *filename, const char *funcname) { Npic_vol_info info; Npic_image *np = NULL; int k; k = NPicVOLReadInfo (f1, &info); if (k != NPIC_SUCCESS) { NpicError (funcname, k, ": file \"%s\"", filename); return NULL; } /* Allocate Image */ switch (info.npic_type) { case NPIC_IMAGE_3C : np = NpicCreateImage_3c (info.zmax, info.ymax, info.xmax, 0, 0, 0); break; case NPIC_IMAGE_3L : np = NpicCreateImage_3l (info.zmax, info.ymax, info.xmax, 0, 0, 0); break; } if (np == NULL) { NpicFreeProps (&info.props); NpicError (funcname, NPIC_ERROR, ": file \"%s\"", filename); return NULL; } /* We put info.props in np->gen.props (which was empty before); the properties will be freed on np destruction. */ memmove (&np->gen.props, &info.props, sizeof(Npic_props)); k = NpicVOLReadDatas (np, f1, &info); if (k != NPIC_SUCCESS) { NpicDestroyImage (np); np = NULL; NpicError (funcname, k, ": file \"%s\"", filename); } return np; } /* * Read infos (i.e text props) in a VOL file, * then store results in struct info. * The file is already fopen. * Return NPIC_SUCCESS, else error code. Silent. * On success, properties have to be freed with NpicPropsFree. */ int NPicVOLReadInfo (FILE *f1, Npic_vol_info *info) { int k, v1, v2; char *line; if (f1 == NULL) return NPIC_ERR_BAD_FD; if (info == NULL) return NPIC_ERR_NULL_PTR; memset (info, 0, sizeof(Npic_vol_info)); /* Read properties until first non-property line */ NpicInitProps (&info->props); while (NpicPropRead (&info->props, f1, &line) == NPIC_SUCCESS) ; /* After the list of properties, a line "." is expected */ k = (line) ? strcmp (line, ".") : 1; free (line); /* was allocated by NpicPropRead */ if (k != 0) { NpicFreeProps (&info->props); return NPIC_ERR_HEADER; } snprintf (info->magic, sizeof(info->magic), "VOL%s", NpicGetPropD(&info->props, "Version", "1")); /* Guess if vol or longvol */ v1 = atoi (NpicGetPropD (&info->props, "Voxel-Size", "0")); v2 = atoi (NpicGetPropD (&info->props, "Lvoxel-Size", "0")); if (v1 == 1 && v2 == 0) info->npic_type = NPIC_IMAGE_3C; else if (v1 == 0 && v2 == 4) info->npic_type = NPIC_IMAGE_3L; else return NPIC_ERR_HEADER; info->npic_dim = 3; /* Check if byteswap is necessary */ info->bswap = 0; if (info->npic_type == NPIC_IMAGE_3L) { const char *e = NpicGetPropD (&info->props, "Lvoxel-Endian", ""); if ( strcmp (e, "") != 0 && strcmp (e, NpicVolEndianL()) != 0) info->bswap = 1; } info->xmax = atoi (NpicGetPropD (&info->props, "X", "-1")); info->ymax = atoi (NpicGetPropD (&info->props, "Y", "-1")); info->zmax = atoi (NpicGetPropD (&info->props, "Z", "-1")); if (info->xmax <= 0 || info->ymax <= 0 || info->zmax <= 0) { NpicFreeProps (&info->props); return NPIC_ERR_HEADER; } /* If Vol format is version 1, jump 13 first chars : int sx + int sy + int sz + char \n (BUG FIXED 03/12/2007) */ if (!NpicHasProp (&info->props, "Version")) k = fscanf (f1, "%*13c"); /* Suppress mandatory properties; only Alpha-Color is kept */ NpicSupprProp (&info->props, "X"); NpicSupprProp (&info->props, "Y"); NpicSupprProp (&info->props, "Z"); NpicSupprProp (&info->props, "Voxel-Size"); NpicSupprProp (&info->props, "Lvoxel-Size"); NpicSupprProp (&info->props, "Int-Endian"); NpicSupprProp (&info->props, "Voxel-Endian"); NpicSupprProp (&info->props, "Lvoxel-Endian"); NpicSupprProp (&info->props, "Version"); return NPIC_SUCCESS; } /* * Read binary datas from f1. * * Return NPIC_SUCCESS, else error code. Silent. */ int NpicVOLReadDatas (Npic_image *np, FILE *f1, Npic_vol_info *info) { return NpicReadRAW (np, f1, info->bswap); } /* * Print infos on file. * Return NPIC_SUCCESS, else error code. Verbose. */ int NpicVOLPrintInfo (const char *filename, Npic_vol_info *info) { int i; printf ("FILENAME \"%s\"\n", filename); if (info == NULL) return NPIC_ERR_NULL_PTR; printf ("MAGIC %s\n", info->magic); printf ("TYPE %s\n", NpicImageTypeName(info->npic_type)); printf ("DIM %d\n", info->npic_dim); printf ("XMAX %d\n", info->xmax); printf ("YMAX %d\n", info->ymax); printf ("ZMAX %d\n", info->zmax); printf ("BSWAP %d\n", info->bswap); for (i = 0; i < info->props.nb; i++) printf ("PROP %s: %s\n", info->props.list[i].key, info->props.list[i].val); return NPIC_SUCCESS; } /* * Used to write Endianness in file. */ const char *NpicVolEndianC () { static union { Npic_c v; char s[sizeof(Npic_c)+1]; } e; int i; for (i = e.v = 0; i < sizeof(e.v); ++i) e.v += (i + '0') << (i*8); e.s[sizeof(e.v)] = 0; return e.s; } const char *NpicVolEndianS () { static union { Npic_s v; char s[sizeof(Npic_s)+1]; } e; int i; for (i = e.v = 0; i < sizeof(e.v); ++i) e.v += (i + '0') << (i*8); e.s[sizeof(e.v)] = 0; return e.s; } const char *NpicVolEndianL () { static union { Npic_l v; char s[sizeof(Npic_l)+1]; } e; int i; for (i = e.v = 0; i < sizeof(e.v); ++i) e.v += (i + '0') << (i*8); e.s[sizeof(e.v)] = 0; return e.s; }