int main(int argc, char **argv) { char *me, *err, *key="strong bad", *value; Nrrd *nrrd; NrrdIoState *io; me = argv[0]; if (2 != argc) usage(me); io = nrrdIoStateNew(); nrrdStateVerboseIO = 10; if (nrrdLoad(nrrd=nrrdNew(), argv[1], NULL)) { fprintf(stderr, "%s: trouble loading \"%s\":\n%s", me, argv[1], err = biffGetDone(NRRD)); free(err); exit(1); } if ((value = nrrdKeyValueGet(nrrd, key))) { fprintf(stderr, "%s: '%s':='%s' (%d)\n", me, key, value, (int)strlen(value)); } else { fprintf(stderr, "%s: value not found for key: %s\n", me, key); } nrrdIoStateNix(io); nrrdNuke(nrrd); exit(0); }
int main(int argc, char *argv[]) { char *me, *fileS; FILE *file; unsigned int llen; NrrdIoState *io; me = argv[0]; if (2 != argc) { /* 0 1 (2) */ fprintf(stderr, "usage: %s <file>\n", me); exit(1); } fileS = argv[1]; if (!( file = myopen(fileS) )) { fprintf(stderr, "%s: couldn't open \"%s\" for reading\n", me, fileS); exit(1); } io = nrrdIoStateNew(); do { if (_nrrdOneLine(&llen, io, file)) { fprintf(stderr, "%s: trouble:\n%s", me, biffGet(NRRD)); exit(1); } if (llen) { printf("%2u |%s|\n", llen, io->line); } } while(llen > 0); nrrdIoStateNix(io); myclose(file); exit(0); }
/* ******** nrrdSave ** ** save a given nrrd to a given filename, with cleverness to guess ** format if not specified by the caller ** ** currently, for NRRD format files, we play the detached header game ** whenever the filename ends in NRRD_EXT_NHDR, and when we play this ** game, the data file is ALWAYS header relative. */ int nrrdSave(const char *filename, const Nrrd *nrrd, NrrdIoState *nio) { char me[]="nrrdSave", err[BIFF_STRLEN]; FILE *file; airArray *mop; if (!(nrrd && filename)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } mop = airMopNew(); if (!nio) { nio = nrrdIoStateNew(); if (!nio) { sprintf(err, "%s: couldn't alloc local NrrdIoState", me); biffAdd(NRRD, err); return 1; } airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); } if (_nrrdEncodingMaybeSet(nio) || _nrrdFormatMaybeGuess(nrrd, nio, filename)) { sprintf(err, "%s: ", me); biffAdd(NRRD, err); airMopError(mop); return 1; } if (nrrdFormatNRRD == nio->format && airEndsWith(filename, NRRD_EXT_NHDR)) { nio->detachedHeader = AIR_TRUE; _nrrdSplitName(&(nio->path), &(nio->base), filename); /* nix the ".nhdr" suffix */ nio->base[strlen(nio->base) - strlen(NRRD_EXT_NHDR)] = 0; /* nrrdFormatNRRD->write will do the rest */ } else { nio->detachedHeader = AIR_FALSE; } if (!( file = airFopen(filename, stdout, "wb") )) { sprintf(err, "%s: couldn't fopen(\"%s\",\"wb\"): %s", me, filename, strerror(errno)); biffAdd(NRRD, err); airMopError(mop); return 1; } airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); if (nrrdWrite(file, nrrd, nio)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
int unrrdu_dataMain(int argc, const char **argv, const char *me, hestParm *hparm) { hestOpt *opt = NULL; char *err, *inS=NULL; Nrrd *nin; NrrdIoState *nio; airArray *mop; int car, pret; mop = airMopNew(); hestOptAdd(&opt, NULL, "nin", airTypeString, 1, 1, &inS, NULL, "input nrrd"); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_dataInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nio = nrrdIoStateNew(); airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); nio->skipData = AIR_TRUE; nio->keepNrrdDataFileOpen = AIR_TRUE; nin = nrrdNew(); airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways); if (nrrdLoad(nin, inS, nio)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error reading header:\n%s", me, err); airMopError(mop); return 1; } if (_nrrdDataFNNumber(nio) > 1) { fprintf(stderr, "%s: sorry, currently can't operate with multiple " "detached datafiles\n", me); airMopError(mop); return 1; } if (!( nrrdFormatNRRD == nio->format )) { fprintf(stderr, "%s: can only print data of NRRD format files\n", me); airMopError(mop); return 1; } car = fgetc(nio->dataFile); #ifdef _MSC_VER /* needed because otherwise printing a carraige return will automatically also produce a newline */ _setmode(_fileno(stdout), _O_BINARY); #endif while (EOF != car) { fputc(car, stdout); car = fgetc(nio->dataFile); } airFclose(nio->dataFile); airMopOkay(mop); return 0; }
int main(int argc, const char *argv[]) { hestOpt *hopt=NULL; airArray *mop; const char *me; char *outS, *err; Nrrd *nin, *nout; NrrdIoState *nio; float heqamount; me = argv[0]; mop = airMopNew(); hestOptAdd(&hopt, "i", "nin", airTypeOther, 1, 1, &nin, NULL, "input nrrd to project. Must be three dimensional.", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "amt", "heq", airTypeFloat, 1, 1, &heqamount, "0.5", "how much to apply histogram equalization to projection images"); hestOptAdd(&hopt, "o", "img out", airTypeString, 1, 1, &outS, NULL, "output image to save to. Will try to use whatever " "format is implied by extension, but will fall back to PPM."); hestParseOrDie(hopt, argc-1, argv+1, NULL, me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); nio = nrrdIoStateNew(); airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); nrrdStateDisableContent = AIR_TRUE; if (doit(nout, nin, 1, heqamount)) { err=biffGetDone(NINSPECT); airMopAdd(mop, err, airFree, airMopAlways); fprintf(stderr, "%s: trouble creating output:\n%s", me, err); airMopError(mop); return 1; } if (nrrdFormatPNG->nameLooksLike(outS) && !nrrdFormatPNG->available()) { fprintf(stderr, "(%s: using PPM format for output)\n", me); nio->format = nrrdFormatPNM; } if (nrrdSave(outS, nout, nio)) { err=biffGetDone(NRRD); airMopAdd(mop, err, airFree, airMopAlways); fprintf(stderr, "%s: trouble saving output image \"%s\":\n%s", me, outS, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
int main(int argc, char **argv) { char *me, *err; Nrrd *nrrd; NrrdIoState *nio; char hstr[] = "NRRD0001\n" "# Complete NRRD file format specification at:\n" "# http://teem.sourceforge.net/nrrd/format.html\n" "# one comment\n" "# two comment\n" "# three comment\n" "type: float\n" "dimension: 2\n" "sizes: 91 114\n" "centerings: node node\n" "endian: big\n" "encoding: raw\n" "bingo:=bob\n" "foo:=super duper fancy bar with corona\n" /* "data file: tmp.raw\n" */; char *wstr; AIR_UNUSED(argc); me = argv[0]; nrrdStateVerboseIO = 10; nio = nrrdIoStateNew(); nrrd = nrrdNew(); nio->path = airStrdup("."); if (nrrdStringRead(nrrd, hstr, nio)) { fprintf(stderr, "%s: trouble reading string:\n%s", me, err = biffGet(NRRD)); free(err); exit(1); } fprintf(stderr, "%s: nrrd->data = %p\n", me, nrrd->data); nrrdSave("out.nrrd", nrrd, NULL); if (nrrdStringWrite(&wstr, nrrd, NULL)) { fprintf(stderr, "%s: trouble writing string:\n%s", me, err = biffGet(NRRD)); free(err); exit(1); } fprintf(stderr, "%s: |%s|\n", me, wstr); free(wstr); nrrdIoStateNix(nio); nrrdNuke(nrrd); exit(0); }
Nrrd* LBLReader::Convert(int t, int c, bool get_max) { int64_t pos = m_path_name.find_last_of('.'); if (pos == -1) return 0; wstring str_name = m_path_name.substr(0, pos); wostringstream strs; strs << str_name /*<< "_t" << t << "_c" << c*/ << ".lbl"; str_name = strs.str(); FILE* lbl_file = 0; if (!WFOPEN(&lbl_file, str_name.c_str(), L"rb")) return 0; Nrrd *output = nrrdNew(); NrrdIoState *nio = nrrdIoStateNew(); nrrdIoStateSet(nio, nrrdIoStateSkipData, AIR_TRUE); if (nrrdRead(output, lbl_file, nio)) { fclose(lbl_file); return 0; } nio = nrrdIoStateNix(nio); rewind(lbl_file); if (output->dim != 3 || (output->type != nrrdTypeInt && output->type != nrrdTypeUInt)) { delete []output->data; nrrdNix(output); fclose(lbl_file); return 0; } int slice_num = int(output->axis[2].size); int x_size = int(output->axis[0].size); int y_size = int(output->axis[1].size); int data_size = slice_num * x_size * y_size; output->data = new unsigned int[data_size]; if (nrrdRead(output, lbl_file, NULL)) { delete []output->data; nrrdNix(output); fclose(lbl_file); return 0; } fclose(lbl_file); return output; }
Nrrd* LBLReader::Convert(int t, int c, bool get_max) { int64_t pos = m_path_name.find_last_of('.'); if (pos == -1) return 0; wstring str_name = m_path_name.substr(0, pos); wostringstream strs; strs << str_name /*<< "_t" << t << "_c" << c*/ << ".lbl"; str_name = strs.str(); Nrrd *output = nrrdNew(); NrrdIoState *nio = nrrdIoStateNew(); nrrdIoStateSet(nio, nrrdIoStateSkipData, AIR_TRUE); string str; str.assign(str_name.length(), 0); for (int i=0; i<(int)str_name.length(); i++) str[i] = (char)str_name[i]; if (nrrdLoad(output, str.c_str(), nio)) return 0; nio = nrrdIoStateNix(nio); if (output->dim != 3 || (output->type != nrrdTypeInt && output->type != nrrdTypeUInt)) { delete []output->data; nrrdNix(output); return 0; } int slice_num = int(output->axis[2].size); int x_size = int(output->axis[0].size); int y_size = int(output->axis[1].size); int data_size = slice_num * x_size * y_size; output->data = new unsigned int[data_size]; if (nrrdLoad(output, str.c_str(), NULL)) { delete []output->data; nrrdNix(output); return 0; } return output; }
/* *************************************************************** */ void reg_io_writeNRRDfile(Nrrd *image, const char *filename) { // Set the encoding to gziped as it is compiled as part of the NiftyReg project NrrdIoState *nio=nrrdIoStateNew(); if (nrrdEncodingGzip->available()){ nrrdIoStateEncodingSet(nio, nrrdEncodingGzip); nrrdIoStateSet(nio, nrrdIoStateZlibLevel, 9); } else{ fprintf(stderr, "[NiftyReg ERROR] Can not compress the file: \"%s\"\n", filename); } char *err; if (nrrdSave(filename, image, nio)){ err = biffGetDone(NRRD); fprintf(stderr, "[NiftyReg ERROR] Can not write the file \"%s\":\n%s\n", filename, err); free(err); exit(1); } return; }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char me[]="nrrdLoad", *filename, *errPtr, errBuff[AIR_STRLEN_MED]; int filenameLen, sizeI[NRRD_DIM_MAX]; mxClassID mtype; size_t sizeZ[NRRD_DIM_MAX]; unsigned int axIdx; Nrrd *nrrd; NrrdIoState *nio; airArray *mop; if (!(1 == nrhs && mxIsChar(prhs[0]))) { sprintf(errBuff, "%s: requires one string argument (the name of the file)", me); mexErrMsgTxt(errBuff); } mop = airMopNew(); filenameLen = mxGetM(prhs[0])*mxGetN(prhs[0])+1; filename = mxCalloc(filenameLen, sizeof(mxChar)); /* managed by Matlab */ mxGetString(prhs[0], filename, filenameLen); nrrd = nrrdNew(); airMopAdd(mop, nrrd, (airMopper)nrrdNix, airMopAlways); nio = nrrdIoStateNew(); airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); nrrdIoStateSet(nio, nrrdIoStateSkipData, AIR_TRUE); /* read header, but no data */ if (nrrdLoad(nrrd, filename, nio)) { errPtr = biffGetDone(NRRD); airMopAdd(mop, errPtr, airFree, airMopAlways); sprintf(errBuff, "%s: trouble reading NRRD header:\n%s", me, errPtr); airMopError(mop); mexErrMsgTxt(errBuff); } mtype = typeNtoM(nrrd->type); if (mxUNKNOWN_CLASS == mtype) { sprintf(errBuff, "%s: sorry, can't handle type %s (%d)", me, airEnumStr(nrrdType, nrrd->type), nrrd->type); airMopError(mop); mexErrMsgTxt(errBuff); } /* allocate matlab array based on nrrd struct */ for (axIdx=0; axIdx<nrrd->dim; axIdx++) { sizeI[axIdx] = nrrd->axis[axIdx].size; } plhs[0]=mxCreateNumericArray(nrrd->dim,sizeI,mtype,mxREAL); /* copy data pointer */ nrrd->data = mxGetPr(plhs[0]); /* read second time, now loading data */ if (nrrdLoad(nrrd, filename, NULL)) { errPtr = biffGetDone(NRRD); airMopAdd(mop, errPtr, airFree, airMopAlways); sprintf(errBuff, "%s: trouble reading NRRD:\n%s", me, errPtr); airMopError(mop); mexErrMsgTxt(errBuff); } airMopOkay(mop); return; }
int NrrdWriter(HxUniformScalarField3* field, const char* filename, int encoding) { // Identify data type int nrrdType = nrrdTypeUnknown; switch ( field->primType() ) { case McPrimType::mc_uint8: nrrdType = nrrdTypeUChar; break; case McPrimType::mc_int8: nrrdType = nrrdTypeChar; break; case McPrimType::mc_uint16: nrrdType = nrrdTypeUShort; break; case McPrimType::mc_int16: nrrdType = nrrdTypeShort; break; case McPrimType::mc_int32: nrrdType = nrrdTypeInt; break; case McPrimType::mc_float: nrrdType = nrrdTypeFloat; break; case McPrimType::mc_double: nrrdType = nrrdTypeDouble; break; default: break; } if(nrrdType == nrrdTypeUnknown) { theMsg->printf("ERROR: unsupported output type: %s for nrrd",field->primType().getName()); return 0; } void* data = field->lattice.dataPtr(); Nrrd *nrrd = nrrdNew(); NrrdIoState *nios = nrrdIoStateNew(); if ( encoding == nrrdEncodingTypeGzip) { if (nrrdEncodingGzip->available() ) { nrrdIoStateEncodingSet( nios, nrrdEncodingGzip ); nrrdIoStateSet( nios, nrrdIoStateZlibLevel, 9 ); } else theMsg->printf("WARNING: Nrrd library does not support Gzip compression encoding.\n Make sure Teem_ZLIB is on in CMAKE when building Nrrd library.\n"); } else if ( encoding == nrrdEncodingTypeBzip2) { if (nrrdEncodingBzip2->available() ) { nrrdIoStateEncodingSet( nios, nrrdEncodingBzip2 ); // nrrdIoStateSet( nios, nrrdIoStateBzip2BlockSize, 9 ); } else theMsg->printf("WARNING: Nrrd library does not support Bzip2 compression encoding.\n Make sure Teem_BZIP2 is on in CMAKE when building Nrrd library.\n"); } else if ( encoding == nrrdEncodingTypeAscii) { nrrdIoStateEncodingSet( nios, nrrdEncodingAscii ); } else { theMsg->printf("ERROR: Unimplemented nrrd encoding type: %d\n",encoding); return 0; } try { if ( nrrdWrap_va( nrrd, data, nrrdType, (size_t)3, (size_t)field->lattice.dimsInt()[0], (size_t)field->lattice.dimsInt()[1], (size_t)field->lattice.dimsInt()[2] ) ) { throw( biffGetDone(NRRD) ); } nrrdSpaceDimensionSet( nrrd, 3 ); // TODO: Would be nice to set space units. How does Amira store this? // if ( writeVolume->MetaKeyExists(CMTK_META_SPACE_UNITS_STRING) ) // { // nrrd->spaceUnits[0] = strdup( writeVolume->m_MetaInformation[CMTK_META_SPACE_UNITS_STRING].c_str() ); // nrrd->spaceUnits[1] = strdup( writeVolume->m_MetaInformation[CMTK_META_SPACE_UNITS_STRING].c_str() ); // nrrd->spaceUnits[2] = strdup( writeVolume->m_MetaInformation[CMTK_META_SPACE_UNITS_STRING].c_str() ); // } int kind[NRRD_DIM_MAX] = { nrrdKindDomain, nrrdKindDomain, nrrdKindDomain }; nrrdAxisInfoSet_nva( nrrd, nrrdAxisInfoKind, kind ); // TODO: Would be nice to write some kind of space if this exists // Fetch bounding box information and voxel size float* bbox = field->bbox(); McVec3f voxelSize = field->getVoxelSize(); // Just deal with space directions orthogonal to data axes // TODO: Fetch transformation and use that double spaceDir[NRRD_DIM_MAX][NRRD_SPACE_DIM_MAX]; for ( int i = 0; i < 3; ++i ) { for ( int j = 0; j < 3; ++j ) { if (i == j) spaceDir[i][j] = (double) voxelSize[i]; else spaceDir[i][j] = 0.0; // Can't assume that memory is zeroed } } nrrdAxisInfoSet_nva( nrrd, nrrdAxisInfoSpaceDirection, spaceDir ); double origin[NRRD_DIM_MAX] = { bbox[0], bbox[2], bbox[4] }; if ( nrrdSpaceOriginSet( nrrd, origin ) ) { throw( biffGetDone(NRRD) ); } nrrdAxisInfoSet_va( nrrd, nrrdAxisInfoLabel, "x", "y", "z" ); if ( nrrdSave( filename, nrrd, nios ) ) { throw( biffGetDone(NRRD) ); } } catch ( char* err ) { theMsg->printf("ERROR: hxNrrdIO library returned error '%s'\n", err); free( err ); return 0; } nrrdIoStateNix( nios ); nrrdNix(nrrd); return 1; }
Nrrd* NRRDReader::Convert(int t, int c, bool get_max) { if (t<0 || t>=m_time_num) return 0; int i; m_data_name = m_4d_seq[t].filename.substr(m_4d_seq[t].filename.find_last_of(GETSLASH())+1); Nrrd *output = nrrdNew(); NrrdIoState *nio = nrrdIoStateNew(); nrrdIoStateSet(nio, nrrdIoStateSkipData, AIR_TRUE); string str; str.assign(m_4d_seq[t].filename.length(), 0); for (i=0; i<(int)m_4d_seq[t].filename.length(); i++) str[i] = (char)m_4d_seq[t].filename[i]; if (nrrdLoad(output, str.c_str(), nio)) return 0; nio = nrrdIoStateNix(nio); if (output->dim != 3) { delete []output->data; nrrdNix(output); return 0; } m_slice_num = int(output->axis[2].size); m_x_size = int(output->axis[0].size); m_y_size = int(output->axis[1].size); m_xspc = output->axis[0].spacing; m_yspc = output->axis[1].spacing; m_zspc = output->axis[2].spacing; if (m_xspc>0.0 && m_xspc<100.0 && m_yspc>0.0 && m_yspc<100.0 && m_zspc>0.0 && m_zspc<100.0) m_valid_spc = true; else { m_valid_spc = false; m_xspc = 1.0; m_yspc = 1.0; m_zspc = 1.0; } int data_size = m_slice_num * m_x_size * m_y_size; if (output->type == nrrdTypeUShort || output->type == nrrdTypeShort) data_size *= 2; output->data = new unsigned char[data_size]; if (nrrdLoad(output, str.c_str(), NULL)) { delete []output->data; nrrdNix(output); return 0; } // turn signed into unsigned if (output->type == nrrdTypeChar) { for (i=0; i<m_slice_num*m_x_size*m_y_size; i++) { char val = ((char*)output->data)[i]; unsigned char n = val + 128; ((unsigned char*)output->data)[i] = n; } output->type = nrrdTypeUChar; } m_max_value = 0.0; // turn signed into unsigned unsigned short min_value = 32768, n; if (output->type == nrrdTypeShort || output->type == nrrdTypeUShort) { for (i=0; i<m_slice_num*m_x_size*m_y_size; i++) { if (output->type == nrrdTypeShort) { short val = ((short*)output->data)[i]; n = val + 32768; ((unsigned short*)output->data)[i] = n; min_value = (n < min_value)?n:min_value; } else { n = ((unsigned short*)output->data)[i]; } if (get_max) m_max_value = (n > m_max_value)?n:m_max_value; } output->type = nrrdTypeUShort; } //find max value if (output->type == nrrdTypeUChar) { //8 bit m_max_value = 255.0; m_scalar_scale = 1.0; } else if (output->type == nrrdTypeUShort) { m_max_value -= min_value; //16 bit for (i=0; i<m_slice_num*m_x_size*m_y_size; i++) { ((unsigned short*)output->data)[i] = ((unsigned short*)output->data)[i] - min_value; } if (m_max_value > 0.0) m_scalar_scale = 65535.0 / m_max_value; else m_scalar_scale = 1.0; } else { delete []output->data; nrrdNix(output); return 0; } m_cur_time = t; return output; }
int unrrdu_dnormMain(int argc, const char **argv, const char *me, hestParm *hparm) { char *outS; int pret; Nrrd *nin, *nout; NrrdIoState *nio; int kindIn, kindOut, headerOnly, haveMM, trivialOrient, recenter, gotmf; unsigned int kindAxis, axi, si, sj; double sscl; hestOpt *opt = NULL; char *err; airArray *mop; hestOptAdd(&opt, "h,header", NULL, airTypeInt, 0, 0, &headerOnly, NULL, "output header of nrrd file only, not the data itself"); hestOptAdd(&opt, "to", NULL, airTypeInt, 0, 0, &trivialOrient, NULL, "(*t*rivial *o*rientation) " "even if the input nrrd comes with full orientation or " "per-axis min-max info, ignore it and instead assert the " "identity mapping between index and world space"); hestOptAdd(&opt, "c,center", NULL, airTypeInt, 0, 0, &recenter, NULL, "re-locate output spaceOrigin so that field is centered " "around origin of space coordinates"); hestOptAdd(&opt, "s,scaling", "scl", airTypeDouble, 1, 1, &sscl, "1.0", "when having to contrive orientation information and there's " "no per-axis min/max to inform what the sample spacing is, " "this is the sample spacing to assert"); OPT_ADD_NIN(nin, "input image"); OPT_ADD_NOUT(outS, "output filename"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_dnormInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); /* can't deal with block type */ if (nrrdTypeBlock == nin->type) { fprintf(stderr, "%s: can only have scalar kinds (not %s)\n", me, airEnumStr(nrrdType, nrrdTypeBlock)); airMopError(mop); exit(1); } /* make sure all kinds are set to something */ /* see if there's a range kind, verify that there's only one */ /* set haveMM */ haveMM = AIR_TRUE; kindIn = nrrdKindUnknown; kindAxis = 0; for (axi=0; axi<nin->dim; axi++) { if (nrrdKindUnknown == nin->axis[axi].kind || nrrdKindIsDomain(nin->axis[axi].kind)) { haveMM &= AIR_EXISTS(nin->axis[axi].min); haveMM &= AIR_EXISTS(nin->axis[axi].max); } else { if (nrrdKindUnknown != kindIn) { fprintf(stderr, "%s: got non-domain kind %s on axis %u, but already " "have %s from axis %u\n", me, airEnumStr(nrrdKind, nin->axis[axi].kind), axi, airEnumStr(nrrdKind, kindIn), kindAxis); airMopError(mop); exit(1); } kindIn = nin->axis[axi].kind; kindAxis = axi; } } /* see if the non-domain kind is something we can interpret as a tensor */ if (nrrdKindUnknown != kindIn) { switch (kindIn) { /* ======= THESE are the kinds that we can possibly output ======= */ case nrrdKind2Vector: case nrrdKind3Vector: case nrrdKind4Vector: case nrrdKind2DSymMatrix: case nrrdKind2DMatrix: case nrrdKind3DSymMatrix: case nrrdKind3DMatrix: /* =============================================================== */ kindOut = kindIn; break; /* Some other kinds are mapped to those above */ case nrrdKind3Color: case nrrdKindRGBColor: kindOut = nrrdKind3Vector; break; case nrrdKind4Color: case nrrdKindRGBAColor: kindOut = nrrdKind4Vector; break; default: fprintf(stderr, "%s: got non-conforming kind %s on axis %u\n", me, airEnumStr(nrrdKind, kindIn), kindAxis); airMopError(mop); exit(1); break; } } else { /* kindIn is nrrdKindUnknown, so its a simple scalar image, and that's what the output will be too; kindOut == nrrdKindUnknown is used in the code below to say "its a scalar image" */ kindOut = nrrdKindUnknown; } /* initialize output by copying */ nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (nrrdCopy(nout, nin)) { airMopAdd(mop, err = biffGet(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble copying:\n%s", me, err); airMopError(mop); exit(1); } /* no comments, either advertising the format URL or anything else */ nio = nrrdIoStateNew(); airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); nio->skipFormatURL = AIR_TRUE; if (headerOnly) { nio->skipData = AIR_TRUE; } nrrdCommentClear(nout); /* no measurement frame */ gotmf = AIR_FALSE; for (si=0; si<NRRD_SPACE_DIM_MAX; si++) { for (sj=0; sj<NRRD_SPACE_DIM_MAX; sj++) { gotmf |= AIR_EXISTS(nout->measurementFrame[si][sj]); } } if (gotmf) { fprintf(stderr, "%s: WARNING: incoming array measurement frame; " "it will be erased on output.\n", me); /* airMopError(mop); exit(1); */ } for (si=0; si<NRRD_SPACE_DIM_MAX; si++) { for (sj=0; sj<NRRD_SPACE_DIM_MAX; sj++) { nout->measurementFrame[si][sj] = AIR_NAN; } } /* no key/value pairs */ nrrdKeyValueClear(nout); /* no content field */ nout->content = airFree(nout->content); /* normalize domain kinds to "space" */ /* turn off centers (Diderot assumes cell-centered, but that could probably stand to be tested and enforced more) */ /* turn off thickness */ /* turn off labels and units */ for (axi=0; axi<nout->dim; axi++) { if (nrrdKindUnknown == kindOut) { nout->axis[axi].kind = nrrdKindSpace; } else { nout->axis[axi].kind = (kindAxis == axi ? kindOut : nrrdKindSpace); } nout->axis[axi].center = nrrdCenterUnknown; nout->axis[axi].thickness = AIR_NAN; nout->axis[axi].label = airFree(nout->axis[axi].label); nout->axis[axi].units = airFree(nout->axis[axi].units); nout->axis[axi].min = AIR_NAN; nout->axis[axi].max = AIR_NAN; nout->axis[axi].spacing = AIR_NAN; } /* logic of orientation definition: If space dimension is known: set origin to zero if not already set set space direction to unit vector if not already set Else if have per-axis min and max: set spae origin and directions to communicate same intent as original per-axis min and max and original centering Else set origin to zero and all space directions to units. It might be nice to use gage's logic for mapping from world to index, but we have to accept a greater variety of kinds and dimensions than gage ever has to process. */ if (nout->spaceDim && !trivialOrient) { int saxi = 0; /* we use only the space dimension, not any named space */ nout->space = nrrdSpaceUnknown; if (!nrrdSpaceVecExists(nout->spaceDim, nout->spaceOrigin)) { nrrdSpaceVecSetZero(nout->spaceOrigin); } for (axi=0; axi<nout->dim; axi++) { if (nrrdKindUnknown == kindOut || kindAxis != axi) { /* its a domain axis of output */ if (!nrrdSpaceVecExists(nout->spaceDim, nout->axis[axi].spaceDirection)) { nrrdSpaceVecSetZero(nout->axis[axi].spaceDirection); nout->axis[axi].spaceDirection[saxi] = sscl; } /* else we leave existing space vector as is */ saxi++; } else { /* else its a range axis */ nrrdSpaceVecSetNaN(nout->axis[axi].spaceDirection); } } } else if (haveMM && !trivialOrient) { int saxi = 0; size_t N; double rng; for (axi=0; axi<nout->dim; axi++) { if (nrrdKindUnknown == kindOut || kindAxis != axi) { /* its a domain axis of output */ nrrdSpaceVecSetZero(nout->axis[axi].spaceDirection); rng = nin->axis[axi].max - nin->axis[axi].min; if (nrrdCenterNode == nin->axis[axi].center) { nout->spaceOrigin[saxi] = nin->axis[axi].min; N = nin->axis[axi].size; nout->axis[axi].spaceDirection[saxi] = rng/(N-1); } else { /* unknown centering treated as cell */ N = nin->axis[axi].size; nout->spaceOrigin[saxi] = nin->axis[axi].min + (rng/N)/2; nout->axis[axi].spaceDirection[saxi] = rng/N; } saxi++; } else { /* else its a range axis */ nrrdSpaceVecSetNaN(nout->axis[axi].spaceDirection); } } nout->spaceDim = saxi; } else { /* either trivialOrient, or, not spaceDim and not haveMM */ int saxi = 0; nout->space = nrrdSpaceUnknown; nrrdSpaceVecSetZero(nout->spaceOrigin); for (axi=0; axi<nout->dim; axi++) { if (nrrdKindUnknown == kindOut || kindAxis != axi) { /* its a domain axis of output */ nrrdSpaceVecSetZero(nout->axis[axi].spaceDirection); nout->axis[axi].spaceDirection[saxi] = (AIR_EXISTS(nin->axis[axi].spacing) ? nin->axis[axi].spacing : sscl); saxi++; } else { /* else its a range axis */ nrrdSpaceVecSetNaN(nout->axis[axi].spaceDirection); } } nout->spaceDim = saxi; } /* space dimension has to match the number of domain axes */ if (nout->dim != nout->spaceDim + !!kindOut) { fprintf(stderr, "%s: output dim %d != spaceDim %d + %d %s%s%s\n", me, nout->dim, nout->spaceDim, !!kindOut, kindOut ? "for non-scalar (" : "(scalar data)", kindOut ? airEnumStr(nrrdKind, kindOut) : "", kindOut ? ") data" : ""); airMopError(mop); exit(1); } if (recenter) { /* sets field's origin so field is centered on the origin. capiche? */ /* this code was tacked on later than the stuff above, so its logic could probably be moved up there, but it seems cleaner to have it as a separate post-process */ double mean[NRRD_SPACE_DIM_MAX]; nrrdSpaceVecSetZero(mean); for (axi=0; axi<nout->dim; axi++) { if (nrrdKindUnknown == kindOut || kindAxis != axi) { nrrdSpaceVecScaleAdd2(mean, 1.0, mean, 0.5*(nout->axis[axi].size - 1), nout->axis[axi].spaceDirection); } } nrrdSpaceVecScaleAdd2(mean, 1.0, mean, 1.0, nout->spaceOrigin); /* now mean is the center of the field */ nrrdSpaceVecScaleAdd2(nout->spaceOrigin, 1.0, nout->spaceOrigin, -1.0, mean); } if (nrrdSave(outS, nout, nio)) { airMopAdd(mop, err = biffGet(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble saving \"%s\":\n%s", me, outS, err); airMopError(mop); exit(1); } airMopOkay(mop); return 0; }
int baneGkms_pvgMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *outS, *perr, err[BIFF_STRLEN], *mapS; Nrrd *ninfo, *nposA, *nposB, *ndon, *npvg; NrrdIoState *nio; airArray *mop; int i, pret, invert, sv, sg, smlI; float *pos, p, min, max, sml, newsml, newmin, newmax; NrrdRange *range; hestOptAdd(&opt, "inv", NULL, airTypeInt, 0, 0, &invert, NULL, "Draw on white background, instead of black"); hestOptAdd(&opt, "m", "mapOut", airTypeString, 1, 1, &mapS, "", "save out the colormap used here, so that it can be applied " "to other nrrds with \"unu imap -r\""); hestOptAdd(&opt, "i", "infoIn", airTypeOther, 1, 1, &ninfo, NULL, "input info file (from \"gkms info\")", NULL, NULL, nrrdHestNrrd); hestOptAdd(&opt, "o", "imageOut", airTypeString, 1, 1, &outS, NULL, "output image, in PPM format"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_baneGkms_pvgInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); airMopAdd(mop, ndon=_baneGkmsDonNew(invert), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nposA=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nposB=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, npvg=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nio=nrrdIoStateNew(), (airMopper)nrrdIoStateNix, airMopAlways); if (airStrlen(mapS)) { if (nrrdSave(mapS, ndon, NULL)) { sprintf(err, "%s: trouble saving colormap", me); biffMove(BANE, err, NRRD); airMopError(mop); return 1; } } /* we use sigma = 1.0: different sigmas will scale the position, which will not change the coloring gthresh = 0.0: we want to see everything, and Simian has taught us that there can be boundaries at extremely low gradients */ if (banePosCalc(nposA, 1.0, 0.0, ninfo)) { sprintf(err, "%s: trouble calculating position", me); biffAdd(BANE, err); airMopError(mop); return 1; } sv = nposA->axis[0].size; sg = nposA->axis[1].size; pos = (float *)nposA->data; /* find min, max, sml, smlI: histo-eq will warp values around such that min-->min and max-->max, but 0-->??. So, find smallest magnitide position (sml) as a stand-in for 0.0 and its index (smlI) */ sml = 0; smlI = 0; min = max = AIR_NAN; for (i=0; i<sv*sg; i++) { p = pos[i]; if (!AIR_EXISTS(p)) continue; if (!AIR_EXISTS(min)) { min = max = p; sml = AIR_ABS(p); smlI = i; continue; } min = AIR_MIN(p, min); max = AIR_MAX(p, max); if (AIR_ABS(p) < sml) { sml = AIR_ABS(p); smlI = i; } } if (!AIR_EXISTS(min)) { sprintf(err, "%s: didn't see any real data in position array", me); biffAdd(BANE, err); airMopError(mop); return 1; } if (nrrdHistoEq(nposB, nposA, NULL, PVG_HISTEQ_BINS, 3, 1.0)) { sprintf(err, "%s: trouble doing histo-eq on p(v,g)", me); biffMove(BANE, err, NRRD); airMopError(mop); return 1; } /* warp position values that pos[smlI] gets mapped back to zero, and so that [newmin,newmax] is centered on zero */ pos = (float *)nposB->data; newsml = pos[smlI]; if (min < -max) { newmin = min; newmax = -min; } else { newmin = -max; newmax = max; } for (i=0; i<sv*sg; i++) { if (!AIR_EXISTS(pos[i])) { continue; } if (pos[i] < newsml) { pos[i] = AIR_CAST(float, AIR_AFFINE(min, pos[i], newsml, newmin, 0.0)); } else {
int unrrdu_basinfoMain(int argc, const char **argv, const char *me, hestParm *hparm) { /* these are stock for unrrdu */ hestOpt *opt = NULL; airArray *mop; int pret; char *err; /* these are stock for things using the usual -i and -o */ char *out; Nrrd *nin, *nout; /* these are specific to this command */ NrrdIoState *nio; char *spcStr, *_origStr, *origStr; int space; unsigned int spaceDim; hestOptAdd(&opt, "spc,space", "space", airTypeString, 1, 1, &spcStr, "", "identify the space (e.g. \"RAS\", \"LPS\") in which the array " "conceptually lives, from the nrrdSpace airEnum, which in turn " "determines the dimension of the space. Or, use an integer>0 to" "give the dimension of a space that nrrdSpace doesn't know about. " "By default (not using this option), the enclosing space is " "set as unknown."); hestOptAdd(&opt, "orig,origin", "origin", airTypeString, 1, 1, &_origStr, "", "(NOTE: must quote vector) the origin in space of the array: " "the location of the center " "of the first sample, of the form \"(x,y,z)\" (or however " "many coefficients are needed for the chosen space). Quoting the " "vector is needed to stop interpretation from the shell"); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); nio = nrrdIoStateNew(); airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); USAGE(_unrrdu_basinfoInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (nrrdCopy(nout, nin)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error copying input:\n%s", me, err); airMopError(mop); return 1; } /* HEY: copy and paste from unrrdu/make.c */ if (airStrlen(spcStr)) { space = airEnumVal(nrrdSpace, spcStr); if (!space) { /* couldn't parse it as space, perhaps its a uint */ if (1 != sscanf(spcStr, "%u", &spaceDim)) { fprintf(stderr, "%s: couldn't parse \"%s\" as a nrrdSpace " "or as a uint", me, spcStr); airMopError(mop); return 1; } /* else we did parse it as a uint */ nout->space = nrrdSpaceUnknown; nout->spaceDim = spaceDim; } else { /* we did parse a known space */ nrrdSpaceSet(nout, space); } } /* HEY: copy and paste from unrrdu/make.c */ if (airStrlen(_origStr)) { /* why this is necessary is a bit confusing to me, both the check for enclosing quotes, and the need to use to a separate variable (isn't hest doing memory management of addresses, not variables?) */ if ('\"' == _origStr[0] && '\"' == _origStr[strlen(_origStr)-1]) { _origStr[strlen(_origStr)-1] = 0; origStr = _origStr + 1; } else { origStr = _origStr; } /* same hack about using NrrdIoState->line as basis for parsing */ nio->line = origStr; nio->pos = 0; if (nrrdFieldInfoParse[nrrdField_space_origin](NULL, nout, nio, AIR_TRUE)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble with origin \"%s\":\n%s", me, origStr, err); nio->line = NULL; airMopError(mop); return 1; } nio->line = NULL; } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }
/* ** _nrrdWrite ** ** Write a nrrd to given file or string (allocated by nrrd), using the ** format and and encoding indicated in nio. Cleverness should be ** isolated and collected here: by the time nio->format->write() is ** called, all writing parameters must be given explicitly, and their ** appropriateness is explicitly tested */ int _nrrdWrite(FILE *file, char **stringP, const Nrrd *nrrd, NrrdIoState *_nio) { char me[]="_nrrdWrite", err[BIFF_STRLEN]; NrrdIoState *nio; airArray *mop; if (!((file || stringP) && nrrd)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } if (file && stringP) { sprintf(err, "%s: can't write to both file and string", me); biffAdd(NRRD, err); return 1; } if (nrrdCheck(nrrd)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); return 1; } mop = airMopNew(); if (_nio) { nio = _nio; } else { nio = nrrdIoStateNew(); if (!nio) { sprintf(err, "%s: couldn't alloc local NrrdIoState", me); biffAdd(NRRD, err); airMopError(mop); return 1; } airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); } if (_nrrdEncodingMaybeSet(nio) || _nrrdFormatMaybeSet(nio)) { sprintf(err, "%s: ", me); biffAdd(NRRD, err); airMopError(mop); return 1; } if (nio->byteSkip || nio->lineSkip) { /* NOTE: unu make bypasses this by calling nrrdFormatNRRD->write() directly */ sprintf(err, "%s: can't generate line or byte skips on data write", me); biffAdd(NRRD, err); airMopError(mop); return 1; } if (stringP) { if (nrrdFormatNRRD != nio->format) { sprintf(err, "%s: sorry, can only write %s files to strings (not %s)", me, nrrdFormatNRRD->name, nio->format->name); biffAdd(NRRD, err); airMopError(mop); return 1; } /* we do this in two passes; first see how much room is needed for the header, then allocate, then write the header */ nio->learningHeaderStrlen = AIR_TRUE; if (nio->format->write(NULL, nrrd, nio)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } *stringP = (char*)malloc(nio->headerStrlen + 1); if (!*stringP) { sprintf(err, "%s: couldn't allocate header string (%u len )", me, nio->headerStrlen); biffAdd(NRRD, err); airMopError(mop); return 1; } nio->learningHeaderStrlen = AIR_FALSE; nio->headerStringWrite = *stringP; if (nio->format->write(NULL, nrrd, nio)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } } else { /* call the writer appropriate for the format */ if (nio->format->write(file, nrrd, nio)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } } airMopOkay(mop); return 0; }
int baneGkms_hvolMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *perr, err[BIFF_STRLEN]; Nrrd *nin, *nout; airArray *mop; int pret, dim[3], lapl, slow, gz = AIR_FALSE; double inc[3*(1+BANE_PARM_NUM)]; baneHVolParm *hvp; NrrdIoState *nio; NrrdKernelSpec *ksp00, *ksp11, *ksp22; hestOptAdd(&opt, "s", "incV incG incH", airTypeOther, 3, 3, inc, "f:1.0 p:0.005 p:0.015", "Strategies for determining how much of the range " "of a quantity should be included and quantized in its axis " "of the histogram volume. Possibilities include:\n " "\b\bo \"f:<F>\": included range is some fraction of the " "total range, as scaled by F\n " "\b\bo \"p:<P>\": exclude the extremal P percent of " "the values\n " "\b\bo \"s:<S>\": included range is S times the standard " "deviation of the values\n " "\b\bo \"a:<min>,<max>\": range is from <min> to <max>", NULL, NULL, baneGkmsHestIncStrategy); hestOptAdd(&opt, "d", "dimV dimG dimH", airTypeInt, 3, 3, dim, "256 256 256", "Dimensions of histogram volume; number of samples along " "each axis"); hestOptAdd(&opt, "k00", "kernel", airTypeOther, 1, 1, &ksp00, "tent", "value reconstruction kernel", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&opt, "k11", "kernel", airTypeOther, 1, 1, &ksp11, "cubicd:1,0", "first derivative kernel", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&opt, "k22", "kernel", airTypeOther, 1, 1, &ksp22, "cubicdd:1,0", "second derivative kernel", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&opt, "l", NULL, airTypeInt, 0, 0, &lapl, NULL, "Use Laplacian instead of Hessian to approximate second " "directional derivative. No faster, less accurate."); hestOptAdd(&opt, "slow", NULL, airTypeInt, 0, 0, &slow, NULL, "Instead of allocating a floating point VGH volume and measuring " "V,G,H once, measure V,G,H multiple times on seperate passes " "(slower, but needs less memory)"); if (nrrdEncodingGzip->available()) { hestOptAdd(&opt, "gz", NULL, airTypeInt, 0, 0, &gz, NULL, "Use gzip compression for output histo-volume; " "much less disk space, slightly slower to read/write"); } hestOptAdd(&opt, "i", "volumeIn", airTypeOther, 1, 1, &nin, NULL, "input scalar volume for which a transfer function is needed", NULL, NULL, nrrdHestNrrd); hestOptAdd(&opt, "o", "hvolOut", airTypeString, 1, 1, &out, NULL, "output histogram volume, used by \"gkms scat\" and " "\"gkms info\""); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_baneGkms_hvolInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); nio = nrrdIoStateNew(); airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); hvp = baneHVolParmNew(); airMopAdd(mop, hvp, (airMopper)baneHVolParmNix, airMopAlways); baneHVolParmGKMSInit(hvp); hvp->makeMeasrVol = !slow; fprintf(stderr, "!%s: need to be using baneHVolParmAxisSet\n", me); /* hvp->axis[0].res = dim[perm[0]]; hvp->axis[1].res = dim[perm[1]]; hvp->axis[2].res = dim[perm[2]]; hvp->axis[1].measr = lapl ? baneMeasrLapl : baneMeasrHess; for (i=0; i<=2; i++) { hvp->ax[i].inc = baneIncArray[(int)inc[(1+BANE_INC_PARM_NUM)*perm[i]]]; for (j=0; j<BANE_INC_PARM_NUM; j++) { hvp->ax[i].incParm[j] = inc[1 + j + (1+BANE_INC_PARM_NUM)*perm[i]]; } } */ hvp->k3pack = AIR_TRUE; nrrdKernelParmSet(&hvp->k[gageKernel00], hvp->kparm[gageKernel00], ksp00); nrrdKernelParmSet(&hvp->k[gageKernel11], hvp->kparm[gageKernel11], ksp11); nrrdKernelParmSet(&hvp->k[gageKernel22], hvp->kparm[gageKernel22], ksp22); if (baneMakeHVol(nout, nin, hvp)) { sprintf(err, "%s: trouble making histogram volume", me); biffAdd(BANE, err); airMopError(mop); return 1; } nio->encoding = gz ? nrrdEncodingGzip : nrrdEncodingRaw; if (nrrdSave(out, nout, nio)) { sprintf(err, "%s: error saving histogram volume", me); biffMove(BANE, err, NRRD); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
int main(int argc, char *argv[]) { char *me; hestOpt *hopt=NULL; airArray *mop; NrrdIoState *nio; FILE *file; char *outS; Nrrd *nin; float width, scale, hack, minX, maxX, minY, maxY; int gray, sx, sy, labels; mop = airMopNew(); me = argv[0]; hestOptAdd(&hopt, "i", "nin", airTypeOther, 1, 1, &nin, NULL, "input image. Must be SQUARE 8-bit RGB or gray", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "w", "width", airTypeFloat, 1, 1, &width, "0.0", "border width to put around triangle, in pixels, " "or \"0\" to not have any border"); hestOptAdd(&hopt, "labels", NULL, airTypeInt, 0, 0, &labels, NULL, "put little labels on things; fix with psfrag in LaTeX"); hestOptAdd(&hopt, "o", "output EPS", airTypeString, 1, 1, &outS, NULL, "output file to render postscript into"); hestParseOrDie(hopt, argc-1, argv+1, NULL, me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); if (!( 2 == nin->dim || 3 == nin->dim )) { fprintf(stderr, "%s: input nrrd must be 2-D or 3-D (not %d-D)\n", me, nin->dim); airMopError(mop); return 1; } if (!( nrrdTypeUChar == nin->type )) { fprintf(stderr, "%s: input nrrd must be type %s (not %s)\n", me, airEnumStr(nrrdType, nrrdTypeUChar), airEnumStr(nrrdType, nin->type)); airMopError(mop); return 1; } sx = (2 == nin->dim ? nin->axis[0].size : nin->axis[1].size); sy = (2 == nin->dim ? nin->axis[1].size : nin->axis[2].size); gray = 2 == nin->dim || 1 == nin->axis[0].size; if (!( sx == sy )) { fprintf(stderr, "%s: image must be square (not %d x %d)\n", me, sx, sy); airMopError(mop); return 1; } if (!( file = airFopen(outS, stdout, "wb") )) { fprintf(stderr, "%s: couldn't open \"%s\" for writing", me, outS); airMopError(mop); return 1; } airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); nio = nrrdIoStateNew(); airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); hack = sqrt(3)/2; /* sorry, copied from nrrd/formatEPS.c */ minX = 0.5; maxX = 8.0; minY = 5.50 - 7.5*hack*sy/sx/2; maxY = 5.50 + 7.5*hack*sy/sx/2; scale = 7.5/sx; minX *= 72; minY *= 72; maxX *= 72; maxY *= 72; scale *= 72; fprintf(file, "%%!PS-Adobe-3.0 EPSF-3.0\n"); fprintf(file, "%%%%Creator: hairy pathetic monster\n"); fprintf(file, "%%%%Title: raving lunatic\n"); fprintf(file, "%%%%Pages: 1\n"); fprintf(file, "%%%%BoundingBox: %d %d %d %d\n", (int)floor(minX), (int)floor(minY), (int)ceil(maxX), (int)ceil(maxY)); fprintf(file, "%%%%HiResBoundingBox: %g %g %g %g\n", minX, minY, maxX, maxY); fprintf(file, "%%%%EndComments\n"); fprintf(file, "%%%%BeginProlog\n"); fprintf(file, "%% linestr creates an empty string to hold " "one scanline\n"); fprintf(file, "/linestr %d string def\n", sx*(gray ? 1 : 3)); fprintf(file, "%%%%EndProlog\n"); fprintf(file, "%%%%Page: 1 1\n"); fprintf(file, "gsave\n"); fprintf(file, "%g %g moveto\n", minX, minY); fprintf(file, "%g %g lineto\n", maxX, minY); fprintf(file, "%g %g lineto\n", (minX + maxX)/2, minY + hack*(maxX - minX)); fprintf(file, "closepath\n"); fprintf(file, "clip\n"); fprintf(file, "gsave newpath\n"); fprintf(file, "%g %g translate\n", minX, minY); fprintf(file, "%g %g scale\n", sx*scale, sy*scale); fprintf(file, "%d %d 8\n", sx, sy); fprintf(file, "[%d 0 0 -%d 0 %d]\n", sx, sy, sy); fprintf(file, "{currentfile linestr readhexstring pop} %s\n", gray ? "image" : "false 3 colorimage"); nrrdEncodingHex->write(file, nin->data, nrrdElementNumber(nin), nin, nio); nio->dataFile = NULL; fprintf(file, "\n"); fprintf(file, "grestore\n"); if (width) { fprintf(file, "%g %g moveto\n", minX, minY); fprintf(file, "%g %g lineto\n", maxX, minY); fprintf(file, "%g %g lineto\n", (minX + maxX)/2, minY + hack*(maxX - minX)); fprintf(file, "closepath\n"); fprintf(file, "%g setlinewidth 0 setgray stroke\n", 2*width*scale); } if (labels) { /* happily, psfrag doesn't respect the clipping path */ fprintf(file, "/Helvetica findfont 20 scalefont setfont\n"); fprintf(file, "%g %g moveto (A) show\n", maxX, minY); fprintf(file, "%g %g moveto (B) show\n", (minX + maxX)/2, minY + hack*(maxX - minX)); fprintf(file, "%g %g moveto (C) show\n", minX, minY); } fprintf(file, "grestore\n"); airMopOkay(mop); return 0; }