1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include "mrilib.h"
8 #include "thd.h"
9 #include "thd_niftiwrite.h"
10 
11 static int error_count = 0 ;
THD_get_write_error_count(void)12 int THD_get_write_error_count(void){ return error_count; }
THD_reset_write_error_count(void)13 void THD_reset_write_error_count(void){ error_count = 0; }
14 
15 static int use_3D_format    = 0 ;  /* 21 Mar 2003 */
16 static int use_NIFTI_format = 0 ;  /* 06 Apr 2005 */
17 static int quiet_overwrite  = 0 ;  /* 31 Jan 2011 */
18 static int update_dset_atr_status = 1; /* 31 Oct 2011 */
19 
THD_use_3D_format(int uu)20 void THD_use_3D_format   ( int uu ){ use_3D_format    = uu; }
THD_use_NIFTI_format(int uu)21 void THD_use_NIFTI_format( int uu ){ use_NIFTI_format = uu; }
THD_set_quiet_overwrite(int uu)22 void THD_set_quiet_overwrite ( int uu ){ quiet_overwrite = uu; }
THD_get_quiet_overwrite()23 int THD_get_quiet_overwrite () { return(quiet_overwrite);}
24 /*----------------------------------------------------------------*/
25 /*! This routine writes all the header data in the struct to
26     the datablock attributes, then writes the dataset to disk.
27 
28    29 Apr 1998: erase attributes that are unused, so that
29                   they won't be left over from a previous life
30 
31    09 Mar 2005: attributes are now set in function
32                 THD_set_dataset_attributes() rather than here
33 
34    06 Apr 2005: might go all NIFTI on you
35 ------------------------------------------------------------------*/
36 
THD_write_3dim_dataset(char * new_sessname,char * new_prefixname,THD_3dim_dataset * dset,RwcBoolean write_brick)37 RwcBoolean THD_write_3dim_dataset( char *new_sessname , char *new_prefixname ,
38                                 THD_3dim_dataset *dset , RwcBoolean write_brick )
39 {
40    THD_datablock *blk ;
41    int ii, cmode ;
42    int is_nsd = 0, is_gifti = 0 ;  /* is NI_SURF_DSET  03 Jul 2006 [rickr] */
43    int free_1d = 0 ;               /* write 1D using prefix */
44    char *ppp ;  /* 06 Apr 2005 */
45    RwcBoolean bb ;
46 
47 ENTRY("THD_write_3dim_dataset") ;
48 
49    /*-- sanity checks --*/
50 
51    if( ! ISVALID_3DIM_DATASET(dset) ){
52      ERROR_message("Cannot write dataset: it is invalid") ;
53      error_count++ ; RETURN(False) ;
54    }
55    if( ! ISVALID_DATABLOCK(dset->dblk) ){
56      ERROR_message("Cannot write dataset: invalid datablock") ;
57      error_count++ ; RETURN(False) ;
58    }
59    if( ! ISVALID_DISKPTR(dset->dblk->diskptr) ){
60      ERROR_message("Cannot write dataset: invalid diskptr") ;
61      error_count++ ; RETURN(False) ;
62    }
63 
64    if( new_prefixname ) ppp = new_prefixname;
65    else                 ppp = DSET_PREFIX(dset);
66 
67    blk = dset->dblk ;
68    blk->parent = (RwcPointer)dset ;  /* 05 Jul 2005 */
69 
70    /* Can only write AFNI formatted datasets */
71    if( DSET_IS_MINC(dset)     ) {
72       fprintf(stderr,"** cannot write '%s', dset is MINC\n",
73               ppp ? ppp : "<NO PREFIX>");
74       error_count++ ; RETURN(False) ;  /* 29 Oct 2001 */
75    }
76    if( DSET_IS_MASTERED(dset) ) {
77       fprintf(stderr,"** cannot write '%s', dset is MASTERED (sub-bricks)\n",
78               ppp ? ppp : "<NO PREFIX>");
79       error_count++ ; RETURN(False) ;  /* 11 Jan 1999 */
80    }
81    if( DSET_IS_ANALYZE(dset)  ) {
82       fprintf(stderr,"** cannot write '%s', dset is ANALYZE\n",
83               ppp ? ppp : "<NO PREFIX>");
84       error_count++ ; RETURN(False) ;  /* 27 Aug 2002 */
85    }
86    if( DSET_IS_CTFMRI(dset)   ) {
87       fprintf(stderr,"** cannot write '%s', dset is CTFMRI\n",
88               ppp ? ppp : "<NO PREFIX>");
89       error_count++ ; RETURN(False) ;  /* 05 Dec 2002 */
90    }
91    if( DSET_IS_CTFSAM(dset)   ) {
92       fprintf(stderr,"** cannot write '%s', dset is CTFSAM\n",
93               ppp ? ppp : "<NO PREFIX>");
94       error_count++ ; RETURN(False) ;  /* 05 Dec 2002 */
95    }
96    if( DSET_IS_TCAT(dset)     ) {
97       fprintf(stderr,"** cannot write '%s', dset is TCAT\n",
98               ppp ? ppp : "<NO PREFIX>");
99       error_count++ ; RETURN(False) ;  /* 05 Aug 2004 */
100    }
101 
102    if( DSET_IS_VOLUMES(dset) && write_brick ) {
103       fprintf(stderr,"** cannot write '%s', dset is VOLUMES\n",
104               ppp ? ppp : "<NO PREFIX>");
105       error_count++ ; RETURN(False) ;  /* 20 Jun 2002 */
106    }
107 
108    /* block NI_SURF_DSET from 1D write    11 Jul 2006 [rickr] */
109    ppp = DSET_PREFIX(dset) ;
110    is_gifti = DSET_IS_GIFTI(dset) || STRING_HAS_SUFFIX(ppp,".gii")
111                                   || STRING_HAS_SUFFIX(ppp,".gii.dset") ;
112    is_nsd = DSET_IS_NI_SURF_DSET(dset) || STRING_HAS_SUFFIX(ppp,".niml.dset") ||
113             is_gifti ;
114 
115    /* might want to block trapping of 1D writes    20 Mar 2008 [rickr] */
116    free_1d = is_nsd || AFNI_yesenv("AFNI_WRITE_1D_AS_PREFIX");
117 
118    if( DSET_IS_1D(dset) ||                 /* block NSD  03 Jul 2006 [rickr] */
119        ( DSET_NY(dset)==1 && DSET_NZ(dset)==1 && !free_1d) ){ /* 04 Mar 2003 */
120 
121      THD_write_1D( new_sessname , new_prefixname , dset ) ;
122      RETURN(True) ;
123    }
124 
125    /*------------------------------*/
126    /*-----  change filenames? -----*/
127 
128    THD_init_diskptr_names( blk->diskptr ,
129                            new_sessname , NULL , new_prefixname ,
130                            dset->view_type , True ) ;
131 
132    /* 15 Aug 2005 */
133 
134    if( !AFNI_yesenv("AFNI_ALLOW_MILLISECONDS") ){ DSET_UNMSEC(dset); }
135 
136    /*----- 09 Mar 2005: set attribute structs in the datablock -----*/
137    if(THD_update_dset_atr_status()) {
138       THD_set_dataset_attributes( dset ) ;
139    }
140 
141    /* The TROSS logger */
142    if ((ppp = my_getenv("AFNI_HISTDB_SCRIPT")) && ppp[0] != '\0') {
143       THD_set_string_atr( dset->dblk , "HISTDB_SCRIPT" , ppp ) ;
144    }
145 
146    /*----- 06 Jun 2007: deconflict dataset name? -----*/
147 
148    /* default is ERROR_exit */
149    if( !THD_ok_overwrite() ){
150      ppp = my_getenv("AFNI_DECONFLICT") ;
151      if( ppp == NULL || toupper(*ppp) != 'O' ){
152        char pfx[THD_MAX_PREFIX] ;
153        MCW_strncpy( pfx , DSET_PREFIX(dset) , THD_MAX_PREFIX ) ;
154        ii = THD_deconflict_prefix( dset ) ;
155        if( ii ){
156          if( ppp && toupper(*ppp) == 'Y' ){
157            WARNING_message("changed output dataset name from '%s' to '%s'",
158                            pfx , DSET_PREFIX(dset) ) ;
159          } else {
160            ERROR_message("output dataset name '%s' conflicts with existing file",pfx);
161            ERROR_message("dataset NOT written to disk!") ;
162            error_count++ ; RETURN(False) ;
163          }
164        }
165      }
166    } else if( THD_is_file(dset->dblk->diskptr->header_name) ||
167               THD_is_file(dset->dblk->diskptr->brick_name)    ){
168      if (!quiet_overwrite) {
169       WARNING_message("Over-writing dataset %s",
170                         dset->dblk->diskptr->header_name);
171      }
172    }
173 
174    /*------ 06 Apr 2005: write a NIFTI-1 dataset??? -----*/
175    /*       11 Oct 2005: allow .hdr suffix also          */
176 
177    ppp = DSET_PREFIX(dset) ;
178    if( STRING_HAS_SUFFIX(ppp,".nii")    ||
179        STRING_HAS_SUFFIX(ppp,".nii.gz") ||
180        STRING_HAS_SUFFIX(ppp,".hdr")    ||
181        use_NIFTI_format                 ||
182        dset->dblk->diskptr->storage_mode == STORAGE_BY_NIFTI){
183 
184      niftiwr_opts_t options ;
185 
186      ii = strlen(DSET_DIRNAME(dset)) + strlen(ppp) + 32 ;
187      options.infile_name = calloc(1,ii) ;
188      strcpy(options.infile_name,DSET_DIRNAME(dset)) ;
189      strcat(options.infile_name,ppp) ;
190 
191      if( !STRING_HAS_SUFFIX(options.infile_name,".nii")    &&
192          !STRING_HAS_SUFFIX(options.infile_name,".nii.gz") &&
193          !STRING_HAS_SUFFIX(options.infile_name,".hdr")      ) /* 11 Oct 2005 */
194        strcat(options.infile_name,".nii") ;
195 
196      /* allow user to order gzip-ed output via environment,
197         OR complain if the file is ordered to be gzip-ed but can't be */
198 
199 
200 #ifdef HAVE_ZLIB                                            /* 21 Sep 2005 */
201 
202 /*     AFNI_yesenv("AFNI_AUTOGZIP")    */
203 /* changed to compress base on AFNI_COMPRESSOR instead */
204 /* do not auto-compress NIFTI, ever, as that alters the NIFTI file name
205  * (and this is not actually where AFNI_COMPRESSOR modifies the file name).
206  *                                                       1 Jun 2021 [rickr] */
207 #if 0
208     /* check env. variable for compression*/
209      cmode = THD_get_write_compression() ;
210      if( (cmode==COMPRESS_GZIP) &&
211          STRING_HAS_SUFFIX(options.infile_name,".nii")   )
212        strcat(options.infile_name,".gz") ;
213 #endif
214 #else
215      if( STRING_HAS_SUFFIX(options.infile_name,".nii.gz") ){
216        WARNING_message("Can't write compressed file '%s'; writing '.nii' instead") ;
217        ii = strlen(options.infile_name) ;
218        options.infile_name[ii-3] = '\0' ;
219      }
220 #endif
221 
222      {  /* set the nifti_io debug level       8 Apr 2005 [rickr] */
223         char * ept = my_getenv("AFNI_NIFTI_DEBUG");
224         if( ept != NULL ) options.debug_level = atoi(ept);
225         else              options.debug_level = 0 ;
226      }
227 
228      if( !write_brick ){
229        ERROR_message("Can't write HEADER only for NIfTI-1 file: %s\n",
230                      options.infile_name ) ;
231        ii = 0 ;
232      } else {
233        ii = THD_write_nifti(dset,options) ;
234        strcpy( dset->dblk->diskptr->brick_name , options.infile_name ) ;
235      }
236 
237      free((void *)options.infile_name) ;
238      if( ii==0 ) error_count++ ;
239      RETURN( (RwcBoolean)ii ) ;
240    }
241 
242    /*------ 21 Mar 2003: use the .3D format? -----*/
243 
244    if( STRING_HAS_SUFFIX(ppp,".3D") || DSET_IS_3D(dset) || use_3D_format ){
245      if( !write_brick ){
246        fprintf(stderr,
247                "** ERROR: can't write HEADER only for .3D file: %s\n",
248                DSET_PREFIX(dset) ) ;
249        error_count++ ; RETURN(False) ;
250      }
251      THD_write_3D( NULL, NULL, dset ) ; RETURN(True) ;
252    }
253 
254    /*------ 12 Jun 2006: use the .niml format -----*/
255 
256    if( STRING_HAS_SUFFIX(ppp,".niml") || DSET_IS_NIML(dset) ){
257      bb = THD_write_niml( dset, write_brick ) ;
258      if( bb == False ) error_count++ ;
259      RETURN(bb) ;
260    }
261 
262    /*------ 28 Jun 2006: use the .niml.dset format -----*/
263 
264    /* if(STRING_HAS_SUFFIX(ppp,".niml.dset") || DSET_IS_NI_SURF_DSET(dset)) */
265    if( is_nsd ){  /* already determined                 03 Jul 2006 [rickr] */
266      if( is_gifti ) bb = THD_write_gifti( dset, write_brick, 0 ) ;
267      else           bb = THD_write_niml( dset, write_brick ) ;
268      if( bb == False ) error_count++ ;
269      RETURN(bb) ;
270    }
271 
272    /*------ 12 May 2020: write in .jpg format? ------*/
273 
274    if( ( STRING_HAS_SUFFIX_CASE(ppp,".jpg") || STRING_HAS_SUFFIX_CASE(ppp,".png") )
275       && DSET_HAS_2D(dset) && DSET_NVALS(dset) == 1 ){
276      bb = (RwcBoolean)mri_write_jpg( ppp , DSET_BRICK(dset,0) ) ;
277      if( bb == False ) error_count++ ;
278      RETURN(bb) ;
279    }
280 
281    /*----- write datablock to disk in AFNI .HEAD/.BRIK format -----*/
282 
283    bb = THD_write_datablock(blk,write_brick) ;
284    if( bb == False ) error_count++ ;
285    RETURN(bb) ;
286 }
287 
288 /* accessor functions to control whether attributes will be reinitialized
289    from dset structure */
290 /* 3drefit turns this off, but all other calls continue to reinitialize
291    attributes. Turning off this reset of the attribute is needed for writing
292    a dataset where items that could get reset like IJK_TO_DICOM_REAL are
293    rewritten using the cardinal transformation */
294 int
THD_update_dset_atr_status()295 THD_update_dset_atr_status()
296 {
297    return(update_dset_atr_status);
298 }
299 
300 void
THD_set_dset_atr_status(int st)301 THD_set_dset_atr_status(int st)
302 {
303    update_dset_atr_status = st;
304 }
305