int main(int argc, char **argv) { /* NIFTI stuff */ nifti_image *nii_ptr; nifti_image nii_rec; int nii_dimids[MAX_NII_DIMS]; int nii_dir[MAX_NII_DIMS]; int nii_map[MAX_NII_DIMS]; unsigned long nii_lens[MAX_NII_DIMS]; int nii_ndims; static int nifti_filetype; static int nifti_datatype; static int nifti_signed = 1; /* MINC stuff */ int mnc_fd; /* MINC file descriptor */ nc_type mnc_type; /* MINC data type as read */ int mnc_ndims; /* MINC image dimension count */ int mnc_dimids[MAX_VAR_DIMS]; /* MINC image dimension identifiers */ long mnc_dlen; /* MINC dimension length value */ double mnc_dstep; /* MINC dimension step value */ int mnc_icv; /* MINC image conversion variable */ int mnc_vid; /* MINC Image variable ID */ long mnc_start[MAX_VAR_DIMS]; /* MINC data starts */ long mnc_count[MAX_VAR_DIMS]; /* MINC data counts */ int mnc_signed; /* MINC if output voxels are signed */ double real_range[2]; /* MINC real range (min, max) */ double input_valid_range[2]; /* MINC valid range (min, max) */ double output_valid_range[2]; /* Valid range of output data. */ double nifti_slope; /* Slope to be applied to output voxels. */ double nifti_inter; /* Intercept to be applied to output voxels. */ double total_valid_range; /* Overall valid range (max - min). */ double total_real_range; /* Overall real range (max - min). */ /* Other stuff */ char out_str[1024]; /* Big string for filename */ char att_str[1024]; /* Big string for attribute values */ int i; /* Generic loop counter the first */ int j; /* Generic loop counter the second */ char *str_ptr; /* Generic ASCIZ string pointer */ int r; /* Result code. */ static int vflag = 0; /* Verbose flag (default is quiet) */ static ArgvInfo argTable[] = { {NULL, ARGV_HELP, NULL, NULL, "Output voxel data type specification"}, {"-byte", ARGV_CONSTANT, (char *)DT_INT8, (char *)&nifti_datatype, "Write voxel data in 8-bit signed integer format."}, {"-short", ARGV_CONSTANT, (char *)DT_INT16, (char *)&nifti_datatype, "Write voxel data in 16-bit signed integer format."}, {"-int", ARGV_CONSTANT, (char *)DT_INT32, (char *)&nifti_datatype, "Write voxel data in 32-bit signed integer format."}, {"-float", ARGV_CONSTANT, (char *)DT_FLOAT32, (char *)&nifti_datatype, "Write voxel data in 32-bit floating point format."}, {"-double", ARGV_CONSTANT, (char *)DT_FLOAT64, (char *)&nifti_datatype, "Write voxel data in 64-bit floating point format."}, {"-signed", ARGV_CONSTANT, (char *)1, (char *)&nifti_signed, "Write integer voxel data in signed format."}, {"-unsigned", ARGV_CONSTANT, (char *)0, (char *)&nifti_signed, "Write integer voxel data in unsigned format."}, {NULL, ARGV_HELP, NULL, NULL, "Output file format specification"}, {"-dual", ARGV_CONSTANT, (char *)FT_NIFTI_DUAL, (char *)&nifti_filetype, "Write NIfTI-1 two-file format (.img and .hdr)"}, {"-ASCII", ARGV_CONSTANT, (char *)FT_NIFTI_ASCII, (char *)&nifti_filetype, "Write NIfTI-1 ASCII header format (.nia)"}, {"-nii", ARGV_CONSTANT, (char *)FT_NIFTI_SINGLE, (char *)&nifti_filetype, "Write NIfTI-1 one-file format (.nii)"}, {"-analyze", ARGV_CONSTANT, (char *)FT_ANALYZE, (char *)&nifti_filetype, "Write an Analyze two-file format file (.img and .hdr)"}, {NULL, ARGV_HELP, NULL, NULL, "Other options"}, {"-quiet", ARGV_CONSTANT, (char *)0, (char *)&vflag, "Quiet operation"}, {"-verbose", ARGV_CONSTANT, (char *)1, (char *)&vflag, "Quiet operation"}, {NULL, ARGV_END, NULL, NULL, NULL} }; ncopts = 0; /* Clear global netCDF error reporting flag */ /* Default NIfTI file type is "NII", single binary file */ nifti_filetype = FT_UNSPECIFIED; nifti_datatype = DT_UNKNOWN; if (ParseArgv(&argc, argv, argTable, 0) || (argc < 2)) { fprintf(stderr, "Too few arguments\n"); return usage(); } if (!nifti_signed) { switch (nifti_datatype) { case DT_INT8: nifti_datatype = DT_UINT8; break; case DT_INT16: nifti_datatype = DT_UINT16; break; case DT_INT32: nifti_datatype = DT_UINT32; break; } } switch (nifti_datatype){ case DT_INT8: case DT_UINT8: mnc_type = NC_BYTE; break; case DT_INT16: case DT_UINT16: mnc_type = NC_SHORT; break; case DT_INT32: case DT_UINT32: mnc_type = NC_INT; break; case DT_FLOAT32: mnc_type = NC_FLOAT; break; case DT_FLOAT64: mnc_type = NC_DOUBLE; break; } if (argc == 2) { strcpy(out_str, argv[1]); str_ptr = strrchr(out_str, '.'); if (str_ptr != NULL && !strcmp(str_ptr, ".mnc")) { *str_ptr = '\0'; } } else if (argc == 3) { strcpy(out_str, argv[2]); str_ptr = strrchr(out_str, '.'); if (str_ptr != NULL) { /* See if a recognized file extension was specified. If so, * we trim it off and set the output file type if none was * specified. If the extension is not recognized, assume * that we will form the filename by just adding the right * extension for the selected output format. */ if (!strcmp(str_ptr, ".nii")) { if (nifti_filetype == FT_UNSPECIFIED) { nifti_filetype = FT_NIFTI_SINGLE; } *str_ptr = '\0'; } else if (!strcmp(str_ptr, ".img") || !strcmp(str_ptr, ".hdr")) { if (nifti_filetype == FT_UNSPECIFIED) { nifti_filetype = FT_NIFTI_DUAL; } *str_ptr = '\0'; } else if (!strcmp(str_ptr, ".nia")) { if (nifti_filetype == FT_UNSPECIFIED) { nifti_filetype = FT_NIFTI_ASCII; } *str_ptr = '\0'; } } } else { fprintf(stderr, "Filename argument required\n"); return usage(); } /* Open the MINC file. It needs to exist. */ mnc_fd = miopen(argv[1], NC_NOWRITE); if (mnc_fd < 0) { fprintf(stderr, "Can't find input file '%s'\n", argv[1]); return (-1); } /* Find the MINC image variable. If we can't find it, there is no * further processing possible... */ mnc_vid = ncvarid(mnc_fd, MIimage); if (mnc_vid < 0) { fprintf(stderr, "Can't locate the image variable (mnc_vid=%d)\n", mnc_vid); return (-1); } /* Find out about the MINC image variable - specifically, how many * dimensions, and which dimensions. */ r = ncvarinq(mnc_fd, mnc_vid, NULL, NULL, &mnc_ndims, mnc_dimids, NULL); if (r < 0) { fprintf(stderr, "Can't read information from image variable\n"); return (-1); } if (mnc_ndims > MAX_NII_DIMS) { fprintf(stderr, "NIfTI-1 files may contain at most %d dimensions\n", MAX_NII_DIMS); return (-1); } /* Initialize the NIfTI structure */ nii_ptr = &nii_rec; init_nifti_header(nii_ptr); /* For now we just use the mnc2nii command line as the description * field. Probably we should use something better, perhaps a * combination of some other standard MINC fields that might * provide more information. */ str_ptr = nii_ptr->descrip; for (i = 0; i < argc; i++) { char *arg_ptr = argv[i]; if ((str_ptr - nii_ptr->descrip) >= MAX_NII_DESCRIP) { break; } if (i != 0) { *str_ptr++ = ' '; } while (*arg_ptr != '\0' && (str_ptr - nii_ptr->descrip) < MAX_NII_DESCRIP) { *str_ptr++ = *arg_ptr++; } *str_ptr = '\0'; } nii_ptr->fname = malloc(strlen(out_str) + 4 + 1); nii_ptr->iname = malloc(strlen(out_str) + 4 + 1); strcpy(nii_ptr->fname, out_str); strcpy(nii_ptr->iname, out_str); switch (nifti_filetype) { case FT_ANALYZE: strcat(nii_ptr->fname, ".hdr"); strcat(nii_ptr->iname, ".img"); break; case FT_NIFTI_SINGLE: strcat(nii_ptr->fname, ".nii"); strcat(nii_ptr->iname, ".nii"); break; case FT_NIFTI_DUAL: strcat(nii_ptr->fname, ".hdr"); strcat(nii_ptr->iname, ".img"); break; case FT_NIFTI_ASCII: strcat(nii_ptr->fname, ".nia"); strcat(nii_ptr->iname, ".nia"); break; default: fprintf(stderr, "Unknown output file type %d\n", nifti_filetype); return (-1); } /* Get real voxel range for the input file. */ miget_image_range(mnc_fd, real_range); /* Get the actual valid voxel value range. */ miget_valid_range(mnc_fd, mnc_vid, input_valid_range); /* Find the default range for the output type. Our output file * will use the full legal range of the output type if it is * an integer. */ if (nifti_datatype == DT_UNKNOWN) { nii_ptr->datatype = DT_FLOAT32; /* Default */ mnc_type = NC_FLOAT; mnc_signed = 1; } else { nii_ptr->datatype = nifti_datatype; mnc_signed = nifti_signed; } if (vflag) { fprintf(stderr, "MINC type %d signed %d\n", mnc_type, mnc_signed); } miget_default_range(mnc_type, mnc_signed, output_valid_range); total_valid_range = input_valid_range[1] - input_valid_range[0]; total_real_range = real_range[1] - real_range[0]; if ((output_valid_range[1] - output_valid_range[0]) > total_valid_range) { /* Empirically, forcing the valid range to be the nearest power * of two greater than the existing valid range seems to improve * the behavior of the conversion. This is at least in part because * of the limited precision of the NIfTI-1 voxel scaling fields. */ double new_range = nearest_power_of_two(total_valid_range); if (new_range - 1.0 >= total_valid_range) { new_range -= 1.0; } if (output_valid_range[1] > total_valid_range) { output_valid_range[0] = 0; output_valid_range[1] = new_range; } else { output_valid_range[1] = output_valid_range[0] + new_range; } } else { /* The new range can't fully represent the input range. Use the * full available range, and warn the user that they may have a * problem. */ printf("WARNING: Range of input exceeds range of output format.\n"); } if (vflag) { printf("Real range: %f %f Input valid range: %f %f Output valid range: %f %f\n", real_range[0], real_range[1], input_valid_range[0], input_valid_range[1], output_valid_range[0], output_valid_range[1]); } /* If the output type is not floating point, we may need to scale the * voxel values. */ if (mnc_type != NC_FLOAT && mnc_type != NC_DOUBLE) { /* Figure out how to map pixel values into the range of the * output datatype. */ nifti_slope = ((real_range[1] - real_range[0]) / (output_valid_range[1] - output_valid_range[0])); if (nifti_slope == 0.0) { nifti_slope = 1.0; } nifti_inter = real_range[0] - (output_valid_range[0] * nifti_slope); /* One problem with NIfTI-1 is the limited precision of the * scl_slope and scl_inter fields (they are just 32-bits). So * we look for possible issues and warn about that here. */ if (nifti_inter != (float) nifti_inter || nifti_slope != (float) nifti_slope) { double epsilon_i = nifti_inter - (float) nifti_inter; double epsilon_s = nifti_slope - (float) nifti_slope; /* If the loss in precision is more than one part per thousand * of the real range, flag this as a problem! */ if ((epsilon_i > total_real_range / 1.0e3) || (epsilon_s > total_real_range / 1.0e3)) { fprintf(stderr, "ERROR: Slope and intercept cannot be represented in the NIfTI-1 header.\n"); fprintf(stderr, " slope %f (%f), intercept %f (%f)\n", nifti_slope, (float) nifti_slope, nifti_inter, (float) nifti_inter); return (-1); } } } else { nifti_slope = 0.0; } nii_ptr->scl_slope = nifti_slope; nii_ptr->scl_inter = nifti_inter; nii_ptr->nvox = 1; /* Initial value for voxel count */ /* Find all of the dimensions of the MINC file, in the order they * will be listed in the NIfTI-1/Analyze file. We use this to build * a map for restructuring the data according to the normal rules * of NIfTI-1. */ nii_ndims = 0; for (i = 0; i < MAX_NII_DIMS; i++) { if (dimnames[i] == NULL) { nii_dimids[nii_ndims] = -1; continue; } nii_dimids[nii_ndims] = ncdimid(mnc_fd, dimnames[i]); if (nii_dimids[nii_ndims] == -1) { continue; } /* Make sure the dimension is actually used to define the image. */ for (j = 0; j < mnc_ndims; j++) { if (nii_dimids[nii_ndims] == mnc_dimids[j]) { nii_map[nii_ndims] = j; break; } } if (j < mnc_ndims) { mnc_dlen = 1; mnc_dstep = 0; ncdiminq(mnc_fd, nii_dimids[nii_ndims], NULL, &mnc_dlen); ncattget(mnc_fd, ncvarid(mnc_fd, dimnames[i]), MIstep, &mnc_dstep); if (mnc_dstep < 0) { nii_dir[nii_ndims] = -1; mnc_dstep = -mnc_dstep; } else { nii_dir[nii_ndims] = 1; } nii_lens[nii_ndims] = mnc_dlen; nii_ndims++; } nii_ptr->dim[dimmap[i]] = (int) mnc_dlen; nii_ptr->nvox *= mnc_dlen; nii_ptr->pixdim[dimmap[i]] = (float) mnc_dstep; } /* Here we do some "post-processing" of the results. Make certain that * the nt value is never zero, and make certain that ndim is set to * 4 if there is a time dimension and 5 if there is a vector dimension */ if (nii_ptr->dim[3] > 1 && nii_ndims < 4) { nii_ndims = 4; } if (nii_ptr->dim[4] > 1) { nii_ptr->intent_code = NIFTI_INTENT_VECTOR; nii_ndims = 5; } nii_ptr->ndim = nii_ndims; /* Total number of dimensions in file */ nii_ptr->nx = nii_ptr->dim[0]; nii_ptr->ny = nii_ptr->dim[1]; nii_ptr->nz = nii_ptr->dim[2]; nii_ptr->nt = nii_ptr->dim[3]; nii_ptr->nu = nii_ptr->dim[4]; nii_ptr->dx = nii_ptr->pixdim[0]; nii_ptr->dy = nii_ptr->pixdim[1]; nii_ptr->dz = nii_ptr->pixdim[2]; nii_ptr->dt = nii_ptr->pixdim[3]; nii_ptr->du = 1; /* MINC files don't define a sample size for a vector_dimension */ nii_ptr->nifti_type = nifti_filetype; /* Load the direction_cosines and start values into the NIfTI-1 * sform structure. * */ for (i = 0; i < MAX_SPACE_DIMS; i++) { int id = ncvarid(mnc_fd, mnc_spatial_names[i]); double start; double step; double dircos[MAX_SPACE_DIMS]; int tmp; if (id < 0) { continue; } /* Set default values */ start = 0.0; step = 1.0; dircos[DIM_X] = dircos[DIM_Y] = dircos[DIM_Z] = 0.0; dircos[i] = 1.0; miattget(mnc_fd, id, MIstart, NC_DOUBLE, 1, &start, &tmp); miattget(mnc_fd, id, MIstep, NC_DOUBLE, 1, &step, &tmp); miattget(mnc_fd, id, MIdirection_cosines, NC_DOUBLE, MAX_SPACE_DIMS, dircos, &tmp); ncdiminq(mnc_fd, ncdimid(mnc_fd, mnc_spatial_names[i]), NULL, &mnc_dlen); if (step < 0) { step = -step; start = start - step * (mnc_dlen - 1); } nii_ptr->sto_xyz.m[0][i] = step * dircos[0]; nii_ptr->sto_xyz.m[1][i] = step * dircos[1]; nii_ptr->sto_xyz.m[2][i] = step * dircos[2]; nii_ptr->sto_xyz.m[0][3] += start * dircos[0]; nii_ptr->sto_xyz.m[1][3] += start * dircos[1]; nii_ptr->sto_xyz.m[2][3] += start * dircos[2]; miattgetstr(mnc_fd, id, MIspacetype, sizeof(att_str), att_str); /* Try to set the S-transform code correctly. */ if (!strcmp(att_str, MI_TALAIRACH)) { nii_ptr->sform_code = NIFTI_XFORM_TALAIRACH; } else if (!strcmp(att_str, MI_CALLOSAL)) { /* TODO: Not clear what do do here... */ nii_ptr->sform_code = NIFTI_XFORM_SCANNER_ANAT; } else { /* MI_NATIVE or unknown */ nii_ptr->sform_code = NIFTI_XFORM_SCANNER_ANAT; } } /* So the last row is right... */ nii_ptr->sto_xyz.m[3][0] = 0.0; nii_ptr->sto_xyz.m[3][1] = 0.0; nii_ptr->sto_xyz.m[3][2] = 0.0; nii_ptr->sto_xyz.m[3][3] = 1.0; nii_ptr->sto_ijk = nifti_mat44_inverse(nii_ptr->sto_xyz); nifti_datatype_sizes(nii_ptr->datatype, &nii_ptr->nbyper, &nii_ptr->swapsize); if (vflag) { nifti_image_infodump(nii_ptr); } /* Now load the actual MINC data. */ nii_ptr->data = malloc(nii_ptr->nbyper * nii_ptr->nvox); if (nii_ptr->data == NULL) { fprintf(stderr, "Out of memory.\n"); return (-1); } mnc_icv = miicv_create(); miicv_setint(mnc_icv, MI_ICV_TYPE, mnc_type); miicv_setstr(mnc_icv, MI_ICV_SIGN, (mnc_signed) ? MI_SIGNED : MI_UNSIGNED); miicv_setdbl(mnc_icv, MI_ICV_VALID_MAX, output_valid_range[1]); miicv_setdbl(mnc_icv, MI_ICV_VALID_MIN, output_valid_range[0]); miicv_setdbl(mnc_icv, MI_ICV_IMAGE_MAX, real_range[1]); miicv_setdbl(mnc_icv, MI_ICV_IMAGE_MIN, real_range[0]); miicv_setdbl(mnc_icv, MI_ICV_DO_NORM, TRUE); miicv_setdbl(mnc_icv, MI_ICV_USER_NORM, TRUE); miicv_attach(mnc_icv, mnc_fd, mnc_vid); /* Read in the entire hyperslab from the file. */ for (i = 0; i < mnc_ndims; i++) { ncdiminq(mnc_fd, mnc_dimids[i], NULL, &mnc_count[i]); mnc_start[i] = 0; } r = miicv_get(mnc_icv, mnc_start, mnc_count, nii_ptr->data); if (r < 0) { fprintf(stderr, "Read error\n"); return (-1); } /* Shut down the MINC stuff now that it has done its work. */ miicv_detach(mnc_icv); miicv_free(mnc_icv); miclose(mnc_fd); if (vflag) { /* Debugging stuff - just to check the contents of these arrays. */ for (i = 0; i < nii_ndims; i++) { printf("%d: %ld %d %d\n", i, nii_lens[i], nii_map[i], nii_dir[i]); } printf("bytes per voxel %d\n", nii_ptr->nbyper); printf("# of voxels %ld\n", nii_ptr->nvox); } /* Rearrange the data to correspond to the NIfTI dimension ordering. */ restructure_array(nii_ndims, nii_ptr->data, nii_lens, nii_ptr->nbyper, nii_map, nii_dir); if (vflag) { /* More debugging stuff - check coordinate transform. */ test_xform(nii_ptr->sto_xyz, 0, 0, 0); test_xform(nii_ptr->sto_xyz, 10, 0, 0); test_xform(nii_ptr->sto_xyz, 0, 10, 0); test_xform(nii_ptr->sto_xyz, 0, 0, 10); test_xform(nii_ptr->sto_xyz, 10, 10, 10); } if (vflag) { fprintf(stdout, "Writing NIfTI-1 file..."); } nifti_image_write(nii_ptr); if (vflag) { fprintf(stdout, "done.\n"); } return (0); }
MNCAPI int minc_load_data(char *path, void *dataptr, int datatype, long *ct, long *cz, long *cy, long *cx, double *dt, double *dz, double *dy, double *dx, void **infoptr) { int fd; /* MINC file descriptor */ nc_type nctype; /* netCDF type */ char *signstr; /* MI_SIGNED or MI_UNSIGNED */ int length; int dim_id[MI_S_NDIMS]; long dim_len[MI_S_NDIMS]; int i, j; /* Generic loop counters */ int var_id; int var_ndims; int var_dims[MAX_NC_DIMS]; int icv; /* MINC image conversion variable */ long start[MI_S_NDIMS]; long count[MI_S_NDIMS]; size_t ucount[MI_S_NDIMS]; int dir[MI_S_NDIMS]; /* Dimension "directions" */ int map[MI_S_NDIMS]; /* Dimension mapping */ int old_ncopts; /* For storing the old state of ncopts */ double *p_dtmp; long *p_ltmp; struct file_info *p_file; struct att_info *p_att; int r; /* Generic return code */ *infoptr = NULL; fd = miopen(path, NC_NOWRITE); if (fd < 0) { return (MINC_STATUS_ERROR); } old_ncopts =get_ncopts(); set_ncopts(0); for (i = 0; i < MI_S_NDIMS; i++) { dim_id[i] = ncdimid(fd, minc_dimnames[i]); if (dim_id[i] >= 0) { ncdiminq(fd, dim_id[i], NULL, &dim_len[i]); var_id = ncvarid(fd, minc_dimnames[i]); ncattinq(fd, var_id, MIstep, &nctype, &length); switch (i) { case MI_S_T: p_ltmp = ct; p_dtmp = dt; break; case MI_S_X: p_ltmp = cx; p_dtmp = dx; break; case MI_S_Y: p_ltmp = cy; p_dtmp = dy; break; case MI_S_Z: p_ltmp = cz; p_dtmp = dz; break; default: return (MINC_STATUS_ERROR); } if (nctype == NC_DOUBLE && length == 1) { ncattget(fd, var_id, MIstep, p_dtmp); } else { *p_dtmp = 0; /* Unknown/not set */ } *p_ltmp = dim_len[i]; } else { dim_len[i] = 0; } } set_ncopts(old_ncopts); var_id = ncvarid(fd, MIimage); ncvarinq(fd, var_id, NULL, &nctype, &var_ndims, var_dims, NULL); if (var_ndims != 3 && var_ndims != 4) { return (MINC_STATUS_ERROR); } /* We want the data to wind up in t, x, y, z order. */ for (i = 0; i < MI_S_NDIMS; i++) { map[i] = -1; } for (i = 0; i < var_ndims; i++) { if (var_dims[i] == dim_id[MI_S_T]) { map[MI_S_T] = i; } else if (var_dims[i] == dim_id[MI_S_X]) { map[MI_S_X] = i; } else if (var_dims[i] == dim_id[MI_S_Y]) { map[MI_S_Y] = i; } else if (var_dims[i] == dim_id[MI_S_Z]) { map[MI_S_Z] = i; } } icv = miicv_create(); minc_simple_to_nc_type(datatype, &nctype, &signstr); miicv_setint(icv, MI_ICV_TYPE, nctype); miicv_setstr(icv, MI_ICV_SIGN, signstr); miicv_attach(icv, fd, var_id); for (i = 0; i < var_ndims; i++) { start[i] = 0; } for (i = 0; i < MI_S_NDIMS; i++) { if (map[i] >= 0) { count[map[i]] = dim_len[i]; } } r = miicv_get(icv, start, count, dataptr); if (r < 0) { return (MINC_STATUS_ERROR); } if (map[MI_S_T] >= 0) { if (*dt < 0) { dir[MI_S_T] = -1; *dt = -*dt; } else { dir[MI_S_T] = 1; } } if (map[MI_S_X] >= 0) { if (*dx < 0) { dir[MI_S_X] = -1; *dx = -*dx; } else { dir[MI_S_X] = 1; } } if (map[MI_S_Y] >= 0) { if (*dy < 0) { dir[MI_S_Y] = -1; *dy = -*dy; } else { dir[MI_S_Y] = 1; } } if (map[MI_S_Z] >= 0) { if (*dz < 0) { dir[MI_S_Z] = -1; *dz = -*dz; } else { dir[MI_S_Z] = 1; } } if (var_ndims == 3) { for (i = 1; i < MI_S_NDIMS; i++) { map[i-1] = map[i]; dir[i-1] = dir[i]; } } j = 0; for (i = 0; i < MI_S_NDIMS; i++) { if (dim_len[i] > 0) { ucount[j++] = dim_len[i]; } } restructure_array(var_ndims, dataptr, ucount, nctypelen(nctype), map, dir); miicv_detach(icv); miicv_free(icv); old_ncopts =get_ncopts(); set_ncopts(0); /* Generate the complete infoptr array. * This is essentially an in-memory copy of the variables and attributes * in the file. */ p_file = (struct file_info *) malloc(sizeof (struct file_info)); ncinquire(fd, &p_file->file_ndims, &p_file->file_nvars, &p_file->file_natts, NULL); p_file->file_atts = (struct att_info *) malloc(sizeof (struct att_info) * p_file->file_natts); p_file->file_vars = (struct var_info *) malloc(sizeof (struct var_info) * p_file->file_nvars); for (i = 0; i < p_file->file_natts; i++) { p_att = &p_file->file_atts[i]; ncattname(fd, NC_GLOBAL, i, p_att->att_name); ncattinq(fd, NC_GLOBAL, p_att->att_name, &p_att->att_type, &p_att->att_len); p_att->att_val = malloc(p_att->att_len * nctypelen(p_att->att_type)); ncattget(fd, NC_GLOBAL, p_att->att_name, p_att->att_val); } for (i = 0; i < p_file->file_nvars; i++) { struct var_info *p_var = &p_file->file_vars[i]; ncvarinq(fd, i, p_var->var_name, &p_var->var_type, &p_var->var_ndims, p_var->var_dims, &p_var->var_natts); p_var->var_atts = malloc(p_var->var_natts * sizeof (struct att_info)); if (ncdimid(fd, p_var->var_name) >= 0) { /* It's a dimension variable, have to treat it specially... */ } for (j = 0; j < p_var->var_natts; j++) { p_att = &p_var->var_atts[j]; ncattname(fd, i, j, p_att->att_name); ncattinq(fd, i, p_att->att_name, &p_att->att_type, &p_att->att_len); p_att->att_val = malloc(p_att->att_len * nctypelen(p_att->att_type)); ncattget(fd, i, p_att->att_name, p_att->att_val); } } *infoptr = p_file; set_ncopts(old_ncopts); miclose(fd); return (MINC_STATUS_OK); }
/** Read/write a hyperslab of data, performing dimension remapping * and data rescaling as needed. */ static int mirw_hyperslab_icv(int opcode, mihandle_t volume, mitype_t buffer_data_type, const misize_t start[], const misize_t count[], void *buffer) { hid_t dset_id = -1; hid_t mspc_id = -1; hid_t fspc_id = -1; hid_t buffer_type_id = -1; int result = MI_ERROR; hsize_t hdf_start[MI2_MAX_VAR_DIMS]; hsize_t hdf_count[MI2_MAX_VAR_DIMS]; int dir[MI2_MAX_VAR_DIMS]; /* Direction vector in file order */ hsize_t ndims; int slice_ndims; int n_different = 0; double volume_valid_min, volume_valid_max; misize_t buffer_size; void *temp_buffer=NULL; size_t icount[MI2_MAX_VAR_DIMS]; int idir[MI2_MAX_VAR_DIMS]; int imap[MI2_MAX_VAR_DIMS]; double *image_slice_max_buffer=NULL; double *image_slice_min_buffer=NULL; int scaling_needed=0; char path[MI2_MAX_PATH]; hsize_t image_slice_start[MI2_MAX_VAR_DIMS]; hsize_t image_slice_count[MI2_MAX_VAR_DIMS]; hsize_t image_slice_length=0; hsize_t total_number_of_slices=0; hsize_t i; int j; /* Disallow write operations to anything but the highest resolution. */ if (opcode == MIRW_OP_WRITE && volume->selected_resolution != 0) { return MI_LOG_ERROR(MI2_MSG_GENERIC,"Trying to write to a volume thumbnail"); } sprintf(path, MI_ROOT_PATH "/image/%d/image", volume->selected_resolution); /*printf("Using:%s\n",path);*/ /* Open the dataset with the specified path */ MI_CHECK_HDF_CALL(dset_id = H5Dopen1(volume->hdf_id, path),"H5Dopen1"); if (dset_id < 0) { return (MI_ERROR); } MI_CHECK_HDF_CALL(fspc_id = H5Dget_space(dset_id),"H5Dget_space"); if (fspc_id < 0) { goto cleanup; } buffer_type_id = mitype_to_hdftype(buffer_data_type, TRUE); if(buffer_type_id<0) { goto cleanup; } ndims = volume->number_of_dims; if (ndims == 0) { /* A scalar volume is possible but extremely unlikely, not to * mention useless! */ mspc_id = H5Screate(H5S_SCALAR); hdf_count[0]=1; } else { n_different = mitranslate_hyperslab_origin(volume, start, count, hdf_start, hdf_count, dir); mspc_id = H5Screate_simple(ndims, hdf_count, NULL); if (mspc_id < 0) { fprintf(stderr,"H5Screate_simple: Fail %s:%d\n",__FILE__,__LINE__); goto cleanup; } } miget_hyperslab_size_hdf(buffer_type_id, ndims, hdf_count, &buffer_size); MI_CHECK_HDF_CALL(result = H5Sselect_hyperslab(fspc_id, H5S_SELECT_SET, hdf_start, NULL, hdf_count, NULL),"H5Sselect_hyperslab"); if (result < 0) { goto cleanup; } if((result=miget_volume_valid_range( volume, &volume_valid_max, &volume_valid_min))<0) { goto cleanup; } #ifdef _DEBUG printf("mirw_hyperslab_icv:Volume:%lx valid_max:%f valid_min:%f scaling:%d n_different:%d\n",(long int)(volume),volume_valid_max,volume_valid_min,volume->has_slice_scaling,n_different); #endif if(volume->has_slice_scaling) { hid_t image_max_fspc_id; hid_t image_min_fspc_id; hid_t scaling_mspc_id; total_number_of_slices=1; image_slice_length=1; scaling_needed=1; image_max_fspc_id=H5Dget_space(volume->imax_id); image_min_fspc_id=H5Dget_space(volume->imin_id); if ( image_max_fspc_id < 0 ) { /*Report error that image-max is not found!*/ return ( MI_ERROR ); } slice_ndims = H5Sget_simple_extent_ndims ( image_max_fspc_id ); if(slice_ndims<0) { /*TODO: report read error somehow*/ fprintf(stderr,"H5Sget_simple_extent_ndims: Fail %s:%d\n",__FILE__,__LINE__); goto cleanup; } if ( (hsize_t)slice_ndims > ndims ) { /*Can this really happen?*/ slice_ndims = ndims; } for ( j = 0; j < slice_ndims; j++ ) { image_slice_count[j] = hdf_count[j]; image_slice_start[j] = hdf_start[j]; if(hdf_count[j]>1) /*avoid zero sized dimensions?*/ total_number_of_slices*=hdf_count[j]; } for (i = slice_ndims; i < ndims; i++ ) { if(hdf_count[i]>1) /*avoid zero sized dimensions?*/ image_slice_length*=hdf_count[i]; image_slice_count[i] = 0; image_slice_start[i] = 0; } image_slice_max_buffer=malloc(total_number_of_slices*sizeof(double)); if(!image_slice_max_buffer) { result=MI_ERROR; MI_LOG_ERROR(MI2_MSG_OUTOFMEM,total_number_of_slices*sizeof(double)); goto cleanup; } image_slice_min_buffer=malloc(total_number_of_slices*sizeof(double)); if(!image_slice_min_buffer) { result=MI_ERROR; MI_LOG_ERROR(MI2_MSG_OUTOFMEM,total_number_of_slices*sizeof(double)); goto cleanup; } scaling_mspc_id = H5Screate_simple(slice_ndims, image_slice_count, NULL); if( (result=H5Sselect_hyperslab(image_max_fspc_id, H5S_SELECT_SET, image_slice_start, NULL, image_slice_count, NULL))>=0 ) { if((result=H5Dread(volume->imax_id, H5T_NATIVE_DOUBLE, scaling_mspc_id, image_max_fspc_id, H5P_DEFAULT,image_slice_max_buffer))<0) { MI_LOG_ERROR(MI2_MSG_HDF5,"H5Dread"); goto cleanup; } } else { MI_LOG_ERROR(MI2_MSG_HDF5,"H5Sselect_hyperslab"); goto cleanup; } if((result=H5Sselect_hyperslab(image_min_fspc_id, H5S_SELECT_SET, image_slice_start, NULL, image_slice_count, NULL))>=0 ) { if((result=H5Dread(volume->imin_id, H5T_NATIVE_DOUBLE, scaling_mspc_id, image_min_fspc_id, H5P_DEFAULT,image_slice_min_buffer))<0) { MI_LOG_ERROR(MI2_MSG_HDF5,"H5Dread"); goto cleanup; } } else { /*TODO: report read error somehow*/ MI_LOG_ERROR(MI2_MSG_HDF5,"H5Sselect_hyperslab"); goto cleanup; } H5Sclose(scaling_mspc_id); H5Sclose(image_max_fspc_id); } else { slice_ndims=0; total_number_of_slices=1; image_slice_max_buffer=malloc(sizeof(double)); image_slice_min_buffer=malloc(sizeof(double)); miget_volume_range(volume,image_slice_max_buffer,image_slice_min_buffer); image_slice_length=1; /*it produces unity scaling*/ scaling_needed=(*image_slice_max_buffer!=volume_valid_max) || (*image_slice_min_buffer!=volume_valid_min); for (i = 0; i < ndims; i++) { image_slice_length *= hdf_count[i]; } #ifdef _DEBUG printf("mirw_hyperslab_icv:Real max:%f min:%f\n",*image_slice_max_buffer,*image_slice_min_buffer); #endif } //A hack to disable interslice scaling when it is not needed according to MINC1 specs if( volume->volume_type==MI_TYPE_FLOAT || volume->volume_type==MI_TYPE_DOUBLE || volume->volume_type==MI_TYPE_FCOMPLEX || volume->volume_type==MI_TYPE_DCOMPLEX ) { scaling_needed=0; } #ifdef _DEBUG printf("mirw_hyperslab_icv:Slice_ndim:%d total_number_of_slices:%d image_slice_length:%d scaling_needed:%d\n",slice_ndims,total_number_of_slices,image_slice_length,scaling_needed); #endif if (opcode == MIRW_OP_READ) { MI_CHECK_HDF_CALL(result = H5Dread(dset_id, buffer_type_id, mspc_id, fspc_id, H5P_DEFAULT, buffer),"H5Dread"); if(result<0) { goto cleanup; } if(scaling_needed) { switch(buffer_data_type) { case MI_TYPE_FLOAT: #ifdef _DEBUG printf("Descaling float\n"); #endif APPLY_DESCALING(float,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_DOUBLE: #ifdef _DEBUG printf("Descaling double\n"); #endif APPLY_DESCALING(double,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_INT: #ifdef _DEBUG printf("Descaling int\n"); #endif APPLY_DESCALING(int,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_UINT: #ifdef _DEBUG printf("Descaling uint\n"); #endif APPLY_DESCALING(unsigned int,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_SHORT: #ifdef _DEBUG printf("Descaling short\n"); #endif APPLY_DESCALING(short,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_USHORT: #ifdef _DEBUG printf("Descaling ushort\n"); #endif APPLY_DESCALING(unsigned short,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_BYTE: #ifdef _DEBUG printf("Descaling byte\n"); #endif APPLY_DESCALING(char,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_UBYTE: #ifdef _DEBUG printf("Descaling ubyte\n"); #endif APPLY_DESCALING(unsigned char,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; default: /*TODO: report unsupported conversion*/ result=MI_ERROR; goto cleanup; } } else { #ifdef _DEBUG printf("Descaling not needed!\n"); #endif } if (n_different != 0 ) { for (i = 0; i < ndims; i++) { icount[i] = count[i]; } restructure_array(ndims, buffer, icount, H5Tget_size(buffer_type_id),volume->dim_indices, dir); /*TODO: check if we managed to restructure the array*/ result=0; } } else { /*opcode != MIRW_OP_READ*/ volume->is_dirty = TRUE; /* Mark as modified. */ if (n_different != 0 ) { /* Invert before calling */ for (i = 0; i < ndims; i++) { icount[volume->dim_indices[i]] = count[i]; idir[volume->dim_indices[i]] = dir[i]; /* this one was correct the original way*/ imap[volume->dim_indices[i]] = i; } } if(scaling_needed || n_different != 0) { /*create temporary copy, to be destroyed*/ temp_buffer=malloc(buffer_size); if(!temp_buffer) { MI_LOG_ERROR(MI2_MSG_OUTOFMEM,buffer_size); result=MI_ERROR; /*TODO: error code?*/ goto cleanup; } memcpy(temp_buffer,buffer,buffer_size); if (n_different != 0 ) restructure_array(ndims, temp_buffer, icount, H5Tget_size(buffer_type_id), imap, idir); if(scaling_needed) { switch(buffer_data_type) { case MI_TYPE_FLOAT: #ifdef _DEBUG printf("scaling float\n"); #endif APPLY_SCALING(float,temp_buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_DOUBLE: #ifdef _DEBUG printf("scaling double\n"); #endif APPLY_SCALING(double,temp_buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_INT: #ifdef _DEBUG printf("scaling int\n"); #endif APPLY_SCALING(int,temp_buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_UINT: #ifdef _DEBUG printf("scaling unsigned int\n"); #endif APPLY_SCALING(unsigned int,temp_buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_SHORT: #ifdef _DEBUG printf("scaling short\n"); #endif APPLY_SCALING(short,temp_buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_USHORT: #ifdef _DEBUG printf("scaling unsigned short\n"); #endif APPLY_SCALING(unsigned short,temp_buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_BYTE: #ifdef _DEBUG printf("scaling char\n"); #endif APPLY_SCALING(char,temp_buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; case MI_TYPE_UBYTE: #ifdef _DEBUG printf("scaling unsigned char\n"); #endif APPLY_SCALING(unsigned char,temp_buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max); break; default: /*TODO: report unsupported conversion*/ result=MI_ERROR; goto cleanup; } } MI_CHECK_HDF_CALL(result = H5Dwrite(dset_id, buffer_type_id, mspc_id, fspc_id, H5P_DEFAULT, temp_buffer),"H5Dwrite"); } else { MI_CHECK_HDF_CALL(result = H5Dwrite(dset_id, buffer_type_id, mspc_id, fspc_id, H5P_DEFAULT, buffer),"H5Dwrite"); } if(result<0) { goto cleanup; } } cleanup: if (buffer_type_id >= 0) { H5Tclose(buffer_type_id); } if (mspc_id >= 0) { H5Sclose(mspc_id); } if (fspc_id >= 0) { H5Sclose(fspc_id); } if ( dset_id >=0 ) { H5Dclose(dset_id); } if(temp_buffer!=NULL) { free(temp_buffer); } if(image_slice_min_buffer!=NULL) { free(image_slice_min_buffer); } if(image_slice_max_buffer!=NULL) { free(image_slice_max_buffer); } return (result); }
/** Read/write a hyperslab of data, performing dimension remapping * and data rescaling as needed. Data in the range (min-max) will map to the appropriate full range of buffer_data_type */ static int mirw_hyperslab_normalized(int opcode, mihandle_t volume, mitype_t buffer_data_type, const misize_t start[], const misize_t count[], double data_min, double data_max, void *buffer) { hid_t dset_id = -1; hid_t mspc_id = -1; hid_t fspc_id = -1; hid_t volume_type_id = -1; hid_t buffer_type_id = -1; int result = MI_ERROR; hsize_t hdf_start[MI2_MAX_VAR_DIMS]; hsize_t hdf_count[MI2_MAX_VAR_DIMS]; int dir[MI2_MAX_VAR_DIMS]; /* Direction vector in file order */ hsize_t ndims; int slice_ndims; int n_different = 0; double volume_valid_min, volume_valid_max; misize_t buffer_size; misize_t input_buffer_size; double *temp_buffer=NULL; size_t icount[MI2_MAX_VAR_DIMS]; int idir[MI2_MAX_VAR_DIMS]; int imap[MI2_MAX_VAR_DIMS]; double *image_slice_max_buffer=NULL; double *image_slice_min_buffer=NULL; char path[MI2_MAX_PATH]; hsize_t image_slice_start[MI2_MAX_VAR_DIMS]; hsize_t image_slice_count[MI2_MAX_VAR_DIMS]; hsize_t image_slice_length=0; hsize_t total_number_of_slices=0; hsize_t i; int j; /* Disallow write operations to anything but the highest resolution. */ if (opcode == MIRW_OP_WRITE && volume->selected_resolution != 0) { /*TODO: report error that we are not dealing with the rihgt image here*/ return (MI_ERROR); } sprintf(path, MI_ROOT_PATH "/image/%d/image", volume->selected_resolution); /* Open the dataset with the specified path */ MI_CHECK_HDF_CALL(dset_id = H5Dopen1(volume->hdf_id, path),"H5Dopen1"); if (dset_id < 0) { return (MI_ERROR); } MI_CHECK_HDF_CALL(fspc_id = H5Dget_space(dset_id),"H5Dget_space"); if (fspc_id < 0) { /*TODO: report can't get dataset*/ goto cleanup; } buffer_type_id = mitype_to_hdftype(buffer_data_type,TRUE); if(buffer_type_id<0) { goto cleanup; } MI_CHECK_HDF_CALL(volume_type_id = H5Tcopy ( H5T_NATIVE_DOUBLE ),"H5Tcopy"); if(volume_type_id<0) { fprintf(stderr,"H5Tcopy: Fail %s:%d\n",__FILE__,__LINE__); goto cleanup; } ndims = volume->number_of_dims; if (ndims == 0) { /* A scalar volume is possible but extremely unlikely, not to * mention useless! */ mspc_id = H5Screate(H5S_SCALAR); } else { n_different = mitranslate_hyperslab_origin(volume,start,count, hdf_start,hdf_count,dir); MI_CHECK_HDF_CALL(mspc_id = H5Screate_simple(ndims, hdf_count, NULL),"H5Screate_simple"); if (mspc_id < 0) { goto cleanup; } } miget_hyperslab_size_hdf(volume_type_id,ndims,hdf_count,&buffer_size); miget_hyperslab_size_hdf(buffer_type_id,ndims,hdf_count,&input_buffer_size); MI_CHECK_HDF_CALL(result = H5Sselect_hyperslab(fspc_id, H5S_SELECT_SET, hdf_start, NULL, hdf_count, NULL),"H5Sselect_hyperslab"); if (result < 0) { goto cleanup; } miget_volume_valid_range( volume, &volume_valid_max, &volume_valid_min); #ifdef _DEBUG printf("mirw_hyperslab_normalized:Volume:%x valid_max:%f valid_min:%f scaling:%d\n",volume,volume_valid_max,volume_valid_min,volume->has_slice_scaling); #endif if(volume->has_slice_scaling && !(volume->volume_type==MI_TYPE_FLOAT || volume->volume_type==MI_TYPE_DOUBLE || volume->volume_type==MI_TYPE_FCOMPLEX || volume->volume_type==MI_TYPE_DCOMPLEX) ) { hid_t image_max_fspc_id; hid_t image_min_fspc_id; hid_t scaling_mspc_id; total_number_of_slices=1; image_slice_length=1; MI_CHECK_HDF_CALL(image_max_fspc_id=H5Dget_space(volume->imax_id),"H5Dget_space"); MI_CHECK_HDF_CALL(image_min_fspc_id=H5Dget_space(volume->imin_id),"H5Dget_space"); if ( image_max_fspc_id < 0 || image_min_fspc_id<0 ) { result=MI_ERROR; goto cleanup; } MI_CHECK_HDF_CALL(slice_ndims = H5Sget_simple_extent_ndims ( image_max_fspc_id ),"H5Sget_simple_extent_ndims"); if(slice_ndims<0) { goto cleanup; } if ( (hsize_t)slice_ndims > ndims ) { /*Can this really happen?*/ slice_ndims = ndims; } for ( j = 0; j < slice_ndims; j++ ) { image_slice_count[j] = hdf_count[j]; image_slice_start[j] = hdf_start[j]; if(hdf_count[j]>1) /*avoid zero sized dimensions?*/ total_number_of_slices*=hdf_count[j]; } for (i = slice_ndims; i < ndims; i++ ) { if(hdf_count[i]>1) /*avoid zero sized dimensions?*/ image_slice_length*=hdf_count[i]; image_slice_count[i] = 0; image_slice_start[i] = 0; } image_slice_max_buffer=malloc(total_number_of_slices*sizeof(double)); image_slice_min_buffer=malloc(total_number_of_slices*sizeof(double)); /*TODO check for allocation failure ?*/ MI_CHECK_HDF_CALL(scaling_mspc_id = H5Screate_simple(slice_ndims, image_slice_count, NULL),"H5Screate_simple"); if( (result=H5Sselect_hyperslab(image_max_fspc_id, H5S_SELECT_SET, image_slice_start, NULL, image_slice_count, NULL))>=0 ) { if( ( result=H5Dread(volume->imax_id, H5T_NATIVE_DOUBLE, scaling_mspc_id, image_max_fspc_id, H5P_DEFAULT,image_slice_max_buffer))<0) { MI_LOG_ERROR(MI2_MSG_HDF5,"H5Dread"); goto cleanup; } } else { MI_LOG_ERROR(MI2_MSG_HDF5,"H5Sselect_hyperslab"); goto cleanup; } if( (result=H5Sselect_hyperslab(image_min_fspc_id, H5S_SELECT_SET, image_slice_start, NULL, image_slice_count, NULL))>=0 ) { if( (result=H5Dread(volume->imin_id, H5T_NATIVE_DOUBLE, scaling_mspc_id, image_min_fspc_id, H5P_DEFAULT,image_slice_min_buffer))<0) { MI_LOG_ERROR(MI2_MSG_HDF5,"H5Dread"); goto cleanup; } } else { MI_LOG_ERROR(MI2_MSG_HDF5,"H5Sselect_hyperslab"); goto cleanup; } H5Sclose(scaling_mspc_id); H5Sclose(image_max_fspc_id); } else { slice_ndims=0; total_number_of_slices=1; image_slice_max_buffer=malloc(sizeof(double)); image_slice_min_buffer=malloc(sizeof(double)); miget_volume_range( volume,image_slice_max_buffer,image_slice_min_buffer ); image_slice_length=1; for (i = 0; i < ndims; i++) { image_slice_length *= hdf_count[i]; } #ifdef _DEBUG printf("mirw_hyperslab_normalized:Real max:%f min:%f\n",*image_slice_max_buffer,*image_slice_min_buffer); #endif } #ifdef _DEBUG printf("mirw_hyperslab_normalized:Slice_ndim:%d total_number_of_slices:%d image_slice_length:%d\n",slice_ndims,total_number_of_slices,image_slice_length); printf("mirw_hyperslab_normalized:data min:%f data max:%f buffer_data_type:%d\n",data_min,data_max,buffer_data_type); #endif /*Allocate temporary Buffer*/ temp_buffer=(double*)malloc(buffer_size); if(!temp_buffer) { MI_LOG_ERROR(MI2_MSG_OUTOFMEM,buffer_size); result=MI_ERROR; goto cleanup; } if (opcode == MIRW_OP_READ) { MI_CHECK_HDF_CALL(result = H5Dread(dset_id, volume_type_id, mspc_id, fspc_id, H5P_DEFAULT, temp_buffer),"H5Dread"); if(result<0) { goto cleanup; } /*WARNING: floating point types will be normalized between 0.0 and 1.0*/ switch(buffer_data_type) { case MI_TYPE_FLOAT: APPLY_DESCALING_NORM(float,temp_buffer,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max,data_min,data_max,0.0f,1.0f); break; case MI_TYPE_DOUBLE: APPLY_DESCALING_NORM(double,temp_buffer,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max,data_min,data_max,0.0,1.0); break; case MI_TYPE_INT: APPLY_DESCALING_NORM(int,temp_buffer,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max,data_min,data_max,INT_MIN,INT_MAX); break; case MI_TYPE_UINT: APPLY_DESCALING_NORM(unsigned int,temp_buffer,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max,data_min,data_max,0,UINT_MAX); break; case MI_TYPE_SHORT: APPLY_DESCALING_NORM(short,temp_buffer,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max,data_min,data_max,SHRT_MIN,SHRT_MAX); break; case MI_TYPE_USHORT: APPLY_DESCALING_NORM(unsigned short,temp_buffer,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max,data_min,data_max,0,USHRT_MAX); break; case MI_TYPE_BYTE: APPLY_DESCALING_NORM(char,temp_buffer,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max,data_min,data_max,SCHAR_MIN,SCHAR_MAX); break; case MI_TYPE_UBYTE: APPLY_DESCALING_NORM(unsigned char,temp_buffer,buffer,image_slice_length,total_number_of_slices,image_slice_min_buffer,image_slice_max_buffer,volume_valid_min,volume_valid_max,data_min,data_max,0,UCHAR_MAX); break; default: /*TODO: report unsupported conversion*/ result=MI_ERROR; goto cleanup; } if (n_different != 0 ) { for (i = 0; i < ndims; i++) { icount[i] = count[i]; } restructure_array(ndims, buffer, icount, H5Tget_size(buffer_type_id),volume->dim_indices, dir); /*TODO: check if we managed to restructure the array*/ result=0; } } else { /*opcode != MIRW_OP_READ*/
/** Read/write a hyperslab of data. This is the simplified function * which performs no value conversion. It is much more efficient than * mirw_hyperslab_icv() */ static int mirw_hyperslab_raw(int opcode, mihandle_t volume, mitype_t midatatype, const misize_t start[], const misize_t count[], void *buffer) { hid_t dset_id = -1; hid_t mspc_id = -1; hid_t fspc_id = -1; hid_t type_id = -1; int result = MI_ERROR; hsize_t hdf_start[MI2_MAX_VAR_DIMS]; hsize_t hdf_count[MI2_MAX_VAR_DIMS]; int dir[MI2_MAX_VAR_DIMS]; /* Direction vector in file order */ int ndims; int n_different = 0; misize_t buffer_size; void *temp_buffer=NULL; char path[MI2_MAX_PATH]; size_t icount[MI2_MAX_VAR_DIMS]; /* Disallow write operations to anything but the highest resolution. */ if (opcode == MIRW_OP_WRITE && volume->selected_resolution != 0) { return MI_LOG_ERROR(MI2_MSG_GENERIC,"Trying to write to a volume thumbnail"); } sprintf(path, MI_ROOT_PATH "/image/%d/image", volume->selected_resolution); /*printf("Using:%s\n",path);*/ /* Open the dataset with the specified path */ MI_CHECK_HDF_CALL(dset_id = H5Dopen1(volume->hdf_id, path),"H5Dopen1"); if (dset_id < 0) { return (MI_ERROR); } MI_CHECK_HDF_CALL(fspc_id = H5Dget_space(dset_id),"H5Dget_space"); if (fspc_id < 0) { /*TODO: report can't get dataset*/ goto cleanup; } MI_CHECK_HDF_CALL(fspc_id = H5Dget_space(dset_id),"H5Dget_space"); if (fspc_id < 0) { goto cleanup; } if (midatatype == MI_TYPE_UNKNOWN) { type_id = H5Tcopy(volume->mtype_id); } else { type_id = mitype_to_hdftype(midatatype, TRUE); } ndims = volume->number_of_dims; if (ndims == 0) { /* A scalar volume is possible but extremely unlikely, not to * mention useless! */ mspc_id = H5Screate(H5S_SCALAR); } else { n_different = mitranslate_hyperslab_origin(volume, start, count, hdf_start, hdf_count, dir); MI_CHECK_HDF_CALL(mspc_id = H5Screate_simple(ndims, hdf_count, NULL),"H5Screate_simple"); if (mspc_id < 0) { goto cleanup; } } MI_CHECK_HDF_CALL(result = H5Sselect_hyperslab(fspc_id, H5S_SELECT_SET, hdf_start, NULL, hdf_count, NULL),"H5Sselect_hyperslab"); if (result < 0) { goto cleanup; } miget_hyperslab_size_hdf(type_id,ndims,hdf_count,&buffer_size); if (opcode == MIRW_OP_READ) { MI_CHECK_HDF_CALL(result = H5Dread(dset_id, type_id, mspc_id, fspc_id, H5P_DEFAULT,buffer),"H5Dread"); /* Restructure the array after reading the data in file orientation. */ if (n_different != 0) { int i; for (i = 0; i < ndims; i++) { icount[i] = count[i]; } restructure_array(ndims, buffer, icount, H5Tget_size(type_id), volume->dim_indices, dir); } } else { volume->is_dirty = TRUE; /* Mark as modified. */ /* Restructure array before writing to file. * TODO: use temporary buffer for that! */ if (n_different != 0) { int idir[MI2_MAX_VAR_DIMS]; int imap[MI2_MAX_VAR_DIMS]; int i; /* Invert before calling */ for (i = 0; i < ndims; i++) { icount[volume->dim_indices[i]] = count[i]; idir[volume->dim_indices[i]] = dir[i]; // this one was correct the original way imap[volume->dim_indices[i]] = i; } /*Use temporary array to preserve input data*/ temp_buffer=malloc(buffer_size); if(temp_buffer==NULL) { /*TODO: report memory error*/ result=MI_ERROR; goto cleanup; } memcpy(temp_buffer,buffer,buffer_size); restructure_array(ndims, temp_buffer, icount, H5Tget_size(type_id), imap, idir); MI_CHECK_HDF_CALL(result = H5Dwrite(dset_id, type_id, mspc_id, fspc_id, H5P_DEFAULT, temp_buffer),"H5Dwrite"); } else { MI_CHECK_HDF_CALL(result = H5Dwrite(dset_id, type_id, mspc_id, fspc_id, H5P_DEFAULT, buffer),"H5Dwrite"); } } cleanup: if (type_id >= 0) { H5Tclose(type_id); } if (mspc_id >= 0) { H5Sclose(mspc_id); } if (fspc_id >= 0) { H5Sclose(fspc_id); } if ( dset_id >=0 ) { H5Dclose(dset_id); } if ( temp_buffer!= NULL) { free( temp_buffer ); } return (result); }