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