diff --git a/CMakeLists.txt b/CMakeLists.txt index 2585aac..92c5191 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,28 @@ endif() # current build behavior option( BUILD_SHARED_LIBS "Toggle building shared libraries." OFF) +# Add options to mimic FSL features, Can manually specify -DFSLSTYLE:BOOL=ON for parity support with makefile +if(NOT FSLSTYLE) + # If FSL_STYLE is not defined, then + option( FSLSTYLE_NAME_CONFLICTS "FSL behavior for name conflicts (generate error if both img.nii and img.nii.gz exists)" OFF) + option( FSLSTYLE_PIGZ_SUPPORT "PIGZ: Use PIGZ parallel compression if environment includes AFNI_COMPRESSOR=PIGZ" OFF) + option( FSLSTYLE_REJECT_COMPLEX "REJECT_COMPLEX: Generate error if file is complex datatype." OFF) +else() + set(FSLSTYLE_NAME_CONFLICTS ON CACHE BOOL "FSL behavior for name conflicts (ambiguous files img.nii and img.nii.gz is an error)" FORCE) + set(FSLSTYLE_PIGZ_SUPPORT ON CACHE BOOL "PIGZ support" FORCE) + set(FSLSTYLE_REJECT_COMPLEX ON CACHE BOOL "Reject complex images." FORCE) +endif() + +if(FSLSTYLE_NAME_CONFLICTS) + ADD_DEFINITIONS(-DFSLSTYLE) +endif() +if(FSLSTYLE_PIGZ_SUPPORT) + ADD_DEFINITIONS(-DPIGZ) +endif() +if(FSLSTYLE_REJECT_COMPLEX) + ADD_DEFINITIONS(-DREJECT_COMPLEX) +endif() + # Include executables as part of the build option(NIFTI_BUILD_APPLICATIONS "Build various utility tools" ON) mark_as_advanced(NIFTI_BUILD_APPLICATIONS) diff --git a/nifti2/Makefile b/nifti2/Makefile index 073af99..6c5eb9f 100644 --- a/nifti2/Makefile +++ b/nifti2/Makefile @@ -9,6 +9,12 @@ CC = gcc IFLAGS = -I. -I../niftilib -I../znzlib CFLAGS = -Wall -std=gnu99 -pedantic $(USEZLIB) $(IFLAGS) + +#run "FSLSTYLE=1 make" for JPEGLS build +ifeq "$(FSLSTYLE)" "1" + CFLAGS += -DFSLSTYLE -DPIGZ -DREJECT_COMPLEX +endif + LLIBS = -lz -lm MISC_OBJS = nifticdf.o znzlib.o diff --git a/nifti2/nifti2_io.c b/nifti2/nifti2_io.c index a274564..1ef3ee7 100644 --- a/nifti2/nifti2_io.c +++ b/nifti2/nifti2_io.c @@ -3740,7 +3740,23 @@ char * nifti_findhdrname(const char* fname) strcpy(hdrname,basename); strcat(hdrname,elist[efirst]); + #ifdef FSLSTYLE + if (nifti_fileexists(hdrname)) { + free(basename); + char *gzname = (char *)calloc(sizeof(char),strlen(hdrname)+8); + strcpy(gzname, hdrname); + strcat(gzname,extzip); + if (nifti_fileexists(gzname)) { + fprintf(stderr,"Image Exception : Multiple possible filenames detected for basename (*.nii, *.nii.gz): %s\n", basename); + free(gzname); + exit(134); + } + free(gzname); + return hdrname; + } + #else if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } + #endif #ifdef HAVE_ZLIB strcat(hdrname,extzip); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } @@ -5288,14 +5304,14 @@ nifti_1_header * nifti_read_n1_hdr(const char * hname, int *swapped, int check) hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if( g_opts.debug > 0 ) - LNI_FERR(fname,"failed to find header file for", hname); + LNI_FERR(fname,"failed to find N1 header file for", hname); return NULL; } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); fp = znzopen( hfile, "rb", nifti_is_gzfile(hfile) ); if( znz_isnull(fp) ){ - if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); + if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open N1 header file",hfile); free(hfile); return NULL; } @@ -5389,7 +5405,7 @@ nifti_2_header * nifti_read_n2_hdr(const char * hname, int * swapped, hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if( g_opts.debug > 0 ) - LNI_FERR(fname,"failed to find header file for", hname); + LNI_FERR(fname,"failed to find N2 header file for", hname); return NULL; } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found N2 header filename '%s'\n",fname,hfile); @@ -5731,7 +5747,7 @@ void * nifti_read_header( const char *hname, int *nver, int check ) hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if(g_opts.debug > 0) - LNI_FERR(fname,"failed to find header file for", hname); + LNI_FERR(fname,"failed to find any header file for", hname); return NULL; /* check return */ } else if( g_opts.debug > 2 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); @@ -5742,7 +5758,7 @@ void * nifti_read_header( const char *hname, int *nver, int check ) /**- open file, separate reading of header, extensions and data */ fp = znzopen(hfile, "rb", nifti_is_gzfile(hfile)); if( znz_isnull(fp) ){ - if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); + if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open any header file",hfile); free(hfile); return NULL; } @@ -5885,7 +5901,7 @@ nifti_image *nifti_image_read( const char *hname , int read_data ) /**- open file, separate reading of header, extensions and data */ fp = znzopen(hfile, "rb", nifti_is_gzfile(hfile)); if( znz_isnull(fp) ){ - if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); + if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open a header file",hfile); free(hfile); return NULL; } @@ -5949,6 +5965,13 @@ nifti_image *nifti_image_read( const char *hname , int read_data ) znzclose(fp); free(hfile); return NULL; } + #ifdef REJECT_COMPLEX + if ((nim->datatype == DT_COMPLEX64) || (nim->datatype == DT_COMPLEX128) || (nim->datatype == DT_COMPLEX256)) { + fprintf(stderr,"Image Exception Unsupported datatype (COMPLEX64): use fslcomplex to manipulate: %s\n", hname); + exit(13); + } + #endif + if( nim == NULL ){ znzclose( fp ) ; /* close the file */ if( g_opts.debug > 0 ) @@ -7473,6 +7496,10 @@ int nifti_convert_nim2n1hdr(const nifti_image * nim, nifti_1_header * hdr) nhdr.qoffset_z = nim->qoffset_z ; nhdr.pixdim[0] = (nim->qfac >= 0.0) ? 1.0F : -1.0F ; } + #ifdef FSLSTYLE + else //this helps for regression testing between this library and fsl, there is no other purpose. Without this you get false alarms + nhdr.pixdim[0] = 1.0; //default if unknown and not needed + #endif if( nim->sform_code > 0 ){ nhdr.sform_code = nim->sform_code ; @@ -7584,6 +7611,10 @@ int nifti_convert_nim2n2hdr(const nifti_image * nim, nifti_2_header * hdr) nhdr.qoffset_z = nim->qoffset_z ; nhdr.pixdim[0] = (nim->qfac >= 0.0) ? 1.0F : -1.0F ; } + #ifdef FSLSTYLE + else //this helps for regression testing between this library and fsl, there is no other purpose. Without this you get false alarms + nhdr.pixdim[0] = 1.0; //default if unknown and not needed + #endif if( nim->sform_code > 0 ){ nhdr.sform_code = nim->sform_code ; @@ -7807,6 +7838,73 @@ znzFile nifti_image_write_hdr_img2(nifti_image *nim, int write_opts, if( imgfile ) *imgfile = fp; \ return 1 ; } while(0) +#ifdef PIGZ +#ifdef HAVE_ZLIB +int doPigz2(nifti_image *nim, struct nifti_2_header nhdr, const nifti_brick_list * NBL) { + FILE *pigzPipe; + char command[768]; + strcpy(command, "pigz" ); + strcat(command, " -n -f > \""); + strcat(command, nim->fname); + strcat(command, "\""); + #ifdef _MSC_VER + if (( pigzPipe = _popen(command, "w")) == NULL) + return -1; + #else + if (( pigzPipe = popen(command, "w")) == NULL) + return -1; + #endif + znzFile fp; + fp = (znzFile) calloc(1,sizeof(struct znzptr)); + fp->zfptr = NULL; + fp->withz = 0; + fp->nzfptr = pigzPipe; + fwrite(&nhdr, sizeof(nhdr), 1, pigzPipe); + if( nim->nifti_type != NIFTI_FTYPE_ANALYZE ) + nifti_write_extensions(fp,nim); + nifti_write_all_data(fp,nim,NBL); + #ifdef _MSC_VER + _pclose(pigzPipe); + #else + pclose(pigzPipe); + #endif + free(fp); + return 0; +} + +int doPigz(nifti_image *nim, struct nifti_1_header nhdr, const nifti_brick_list * NBL) { + FILE *pigzPipe; + char command[768]; + strcpy(command, "pigz" ); + strcat(command, " -n -f > \""); + strcat(command, nim->fname); + strcat(command, "\""); + #ifdef _MSC_VER + if (( pigzPipe = _popen(command, "w")) == NULL) + return -1; + #else + if (( pigzPipe = popen(command, "w")) == NULL) + return -1; + #endif + znzFile fp; + fp = (znzFile) calloc(1,sizeof(struct znzptr)); + fp->zfptr = NULL; + fp->withz = 0; + fp->nzfptr = pigzPipe; + fwrite(&nhdr, sizeof(nhdr), 1, pigzPipe); + if( nim->nifti_type != NIFTI_FTYPE_ANALYZE ) + nifti_write_extensions(fp,nim); + nifti_write_all_data(fp,nim,NBL); + #ifdef _MSC_VER + _pclose(pigzPipe); + #else + pclose(pigzPipe); + #endif + free(fp); + return 0; +} +#endif //HAVE_ZLIB +#endif //PIGZ /* ----------------------------------------------------------------------*/ /*! This writes the header (and optionally the image data) to file @@ -7915,6 +8013,28 @@ static int nifti_image_write_engine(nifti_image *nim, int write_opts, /* we will write the header to a new file */ if( g_opts.debug > 2 ) fprintf(stderr,"+d opening output file %s [%s]\n",nim->fname,opts); + + #ifdef PIGZ + #ifdef HAVE_ZLIB + if ((( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) || (nim->nifti_type == NIFTI_FTYPE_NIFTI2_1 )) && (nifti_is_gzfile(nim->fname)) && (!leave_open) && (write_data) ) { + const char *key = "AFNI_COMPRESSOR"; + char *value; + value = getenv(key); + //export AFNI_COMPRESSOR=PIGZ + char pigzKey[5] = "PIGZ"; + if ((value != NULL) && (strstr(value,pigzKey))) { + if( nver == 2 ) { + if (doPigz2(nim, n2hdr, NBL) == 0) + return 0; + } else { + if (doPigz(nim, n1hdr, NBL) == 0) //success writing with pigz + return 0; + } + } + } + #endif //HAVE_ZLIB + #endif //PIGZ + fp = znzopen( nim->fname , opts , nifti_is_gzfile(nim->fname) ) ; if( znz_isnull(fp) ){ LNI_FERR(func,"cannot open output file",nim->fname); diff --git a/nifti2/nifti_tool.c b/nifti2/nifti_tool.c index 836e673..eccde01 100644 --- a/nifti2/nifti_tool.c +++ b/nifti2/nifti_tool.c @@ -4045,7 +4045,7 @@ static int convert_datatype(nifti_image * nim, nifti_brick_list * NBL, fprintf(stderr, "++ convert datatype: %s to %s, v,f = %d,%d\n", nifti_datatype_to_string(nim->datatype), nifti_datatype_to_string(new_type), verify, fail_choice); - fprintf(stderr, " lossless = %d\n", + fprintf(stderr, " lossless = %d\n", is_lossless(nim->datatype, new_type)); } @@ -4205,7 +4205,7 @@ static int convert_NBL_data(nifti_brick_list * NBL, int old_type, int new_type, /*---------------------------------------------------------------------- * perform actual data conversion (basic checks are already done) * - * It is not clear how to do this without an NxN set of cases, since + * It is not clear how to do this without an NxN set of cases, since * the types must be explicitly noted for each pair, even with macros. * * So it is all written out, even when in and out types match, so that @@ -5459,7 +5459,7 @@ static int is_lossless(int old_type, int new_type) int has_int_space; /* is there int/mati ssa space? */ /*-- invalid types are either binary (bits) or unknown --*/ - if( ! nifti_datatype_is_valid(old_type, 1) || + if( ! nifti_datatype_is_valid(old_type, 1) || ! nifti_datatype_is_valid(new_type, 1) ) { if( g_debug > 0 ) fprintf(stderr,"** is_lossless: invalid types %d, %d\n", @@ -5472,7 +5472,7 @@ static int is_lossless(int old_type, int new_type) o_signed = type_is_signed(old_type); /* signed? */ n_signed = type_is_signed(new_type); o_inttyp = nifti_is_inttype(old_type); /* integral? only using old */ - + /* RGB? */ o_rgbtyp = ( old_type == NIFTI_TYPE_RGB24 || old_type == NIFTI_TYPE_RGBA32 ); n_rgbtyp = ( new_type == NIFTI_TYPE_RGB24 || new_type == NIFTI_TYPE_RGBA32 ); @@ -6997,7 +6997,7 @@ int nt_run_misc_nim_tests(nifti_image * nim) } /* test expansion of ints, as 32-bits, not usually used */ - { + { int * ilist = NULL; const char * istr = "7,4,2..5,11..$"; ilist = nifti_get_intlist(15, istr); @@ -7017,7 +7017,7 @@ static int nt_test_dmat44_quatern(nifti_image * nim) float fb, fc, fd, fx, fy, fz; float x, y, z, fac; - + fputc('\n', stdout); /* and the orthogonalized form */ printf("= sform vs. orthog sform:\n"); @@ -7205,7 +7205,7 @@ int act_cbl( nt_opts * opts ) /*---------------------------------------------------------------------- * copy an image to a new file - * + * * This is a straight NIFTI copy, without cbl (so upper dims are intact). * * Note: nt_image_read() allows for modifications, e.g. to the datatype. diff --git a/niftilib/nifti1_io.c b/niftilib/nifti1_io.c index a1b8ef8..624c41e 100644 --- a/niftilib/nifti1_io.c +++ b/niftilib/nifti1_io.c @@ -2802,7 +2802,23 @@ char * nifti_findhdrname(const char* fname) strcpy(hdrname,basename); strcat(hdrname,elist[efirst]); + #ifdef FSLSTYLE + if (nifti_fileexists(hdrname)) { + free(basename); + char *gzname = (char *)calloc(sizeof(char),strlen(hdrname)+8); + strcpy(gzname, hdrname); + strcat(gzname,extzip); + if (nifti_fileexists(gzname)) { + fprintf(stderr,"Image Exception : Multiple possible filenames detected for basename (*.nii, *.nii.gz): %s\n", basename); + free(gzname); + exit(134); + } + free(gzname); + return hdrname; + } + #else if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } + #endif #ifdef HAVE_ZLIB strcat(hdrname,extzip); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } @@ -4259,6 +4275,13 @@ nifti_image *nifti_image_read( const char *hname , int read_data ) /**- convert all nhdr fields to nifti_image fields */ nim = nifti_convert_nhdr2nim(nhdr,hfile); + #ifdef REJECT_COMPLEX + if ((nim->datatype == DT_COMPLEX64) || (nim->datatype == DT_COMPLEX128) || (nim->datatype == DT_COMPLEX256)) { + fprintf(stderr,"Image Exception Unsupported datatype (COMPLEX64): use fslcomplex to manipulate: %s\n", hname); + exit(13); + } + #endif + if( nim == NULL ){ znzclose( fp ) ; /* close the file */ if( g_opts.debug > 0 ) @@ -5527,6 +5550,10 @@ struct nifti_1_header nifti_convert_nim2nhdr(const nifti_image * nim) nhdr.qoffset_z = nim->qoffset_z ; nhdr.pixdim[0] = (nim->qfac >= 0.0) ? 1.0F : -1.0F ; } + #ifdef FSLSTYLE + else //this helps for regression testing between this library and fsl, there is no other purpose. Without this you get false alarms + nhdr.pixdim[0] = 1.0; //default if unknown and not needed + #endif if( nim->sform_code > 0 ){ nhdr.sform_code = nim->sform_code ; @@ -5728,6 +5755,73 @@ znzFile nifti_image_write_hdr_img2(nifti_image *nim, int write_opts, if( imgfile ) *imgfile = fp; \ return 1 ; } while(0) +#ifdef PIGZ +#ifdef HAVE_ZLIB +int doPigz2(nifti_image *nim, struct nifti_1_header nhdr, const nifti_brick_list * NBL) { + FILE *pigzPipe; + char command[768]; + strcpy(command, "pigz" ); + strcat(command, " -n -f > \""); + strcat(command, nim->fname); + strcat(command, "\""); + #ifdef _MSC_VER + if (( pigzPipe = _popen(command, "w")) == NULL) + return -1; + #else + if (( pigzPipe = popen(command, "w")) == NULL) + return -1; + #endif + znzFile fp; + fp = (znzFile) calloc(1,sizeof(struct znzptr)); + fp->zfptr = NULL; + fp->withz = 0; + fp->nzfptr = pigzPipe; + fwrite(&nhdr, sizeof(nhdr), 1, pigzPipe); + if( nim->nifti_type != NIFTI_FTYPE_ANALYZE ) + nifti_write_extensions(fp,nim); + nifti_write_all_data(fp,nim,NBL); + #ifdef _MSC_VER + _pclose(pigzPipe); + #else + pclose(pigzPipe); + #endif + free(fp); + return 0; +} + +int doPigz(nifti_image *nim, struct nifti_1_header nhdr, const nifti_brick_list * NBL) { + FILE *pigzPipe; + char command[768]; + strcpy(command, "pigz" ); + strcat(command, " -n -f > \""); + strcat(command, nim->fname); + strcat(command, "\""); + #ifdef _MSC_VER + if (( pigzPipe = _popen(command, "w")) == NULL) + return -1; + #else + if (( pigzPipe = popen(command, "w")) == NULL) + return -1; + #endif + znzFile fp; + fp = (znzFile) calloc(1,sizeof(struct znzptr)); + fp->zfptr = NULL; + fp->withz = 0; + fp->nzfptr = pigzPipe; + fwrite(&nhdr, sizeof(nhdr), 1, pigzPipe); + if( nim->nifti_type != NIFTI_FTYPE_ANALYZE ) + nifti_write_extensions(fp,nim); + nifti_write_all_data(fp,nim,NBL); + #ifdef _MSC_VER + _pclose(pigzPipe); + #else + pclose(pigzPipe); + #endif + free(fp); + return 0; +} +#endif //HAVE_ZLIB +#endif //PIGZ /* ----------------------------------------------------------------------*/ /*! This writes the header (and optionally the image data) to file @@ -5816,6 +5910,23 @@ static int nifti_image_write_engine(nifti_image *nim, int write_opts, /* we will write the header to a new file */ if( g_opts.debug > 2 ) fprintf(stderr,"+d opening output file %s [%s]\n",nim->fname,opts); + + #ifdef PIGZ + #ifdef HAVE_ZLIB + if ((( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 )) && (nifti_is_gzfile(nim->fname)) && (!leave_open) && (write_data) ) { + const char *key = "AFNI_COMPRESSOR"; + char *value; + value = getenv(key); + //export AFNI_COMPRESSOR=PIGZ + char pigzKey[5] = "PIGZ"; + if ((value != NULL) && (strstr(value,pigzKey))) { + if (doPigz(nim, nhdr, NBL) == 0) //success writing with pigz + return 0; + } + } + #endif //HAVE_ZLIB + #endif //PIGZ + fp = znzopen( nim->fname , opts , nifti_is_gzfile(nim->fname) ) ; if( znz_isnull(fp) ){ LNI_FERR(func,"cannot open output file",nim->fname);