00001 #include "mrilib.h"
00002 #include "thd_niftiwrite.h"
00003
00004
00005
00006 nifti_image * populate_nifti_image(THD_3dim_dataset *dset, niftiwr_opts_t options) ;
00007
00008 void nifti_set_afni_extension(THD_3dim_dataset *dset,nifti_image *nim) ;
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 int THD_write_nifti( THD_3dim_dataset *dset, niftiwr_opts_t options )
00020 {
00021 nifti_image * nim ;
00022 nifti_brick_list nbl ;
00023 int ii ;
00024 char * fname ;
00025
00026 ENTRY("THD_write_nifti") ;
00027
00028 nifti_set_debug_level(options.debug_level) ;
00029
00030
00031
00032 fname = nifti_strdup(options.infile_name );
00033
00034 if( !THD_filename_ok(fname) || fname[0] == '-' ){
00035 fprintf(stderr,"** ERROR: Illegal filename for NIFTI output: %s\n",
00036 (fname != NULL) ? fname : "(null)" ) ;
00037 RETURN(0) ;
00038 }
00039
00040 if( !ISVALID_DSET(dset) ){
00041 fprintf(stderr,
00042 "** ERROR: Illegal input dataset for NIFTI output: %s\n",
00043 fname ) ;
00044 RETURN(0) ;
00045 }
00046
00047
00048
00049 DSET_load(dset) ;
00050 if( !DSET_LOADED(dset) ){
00051 fprintf(stderr,
00052 "** ERROR: Can't write NIFTI file since dataset isn't loaded: %s\n", fname) ;
00053 RETURN(0) ;
00054 }
00055
00056 nim = populate_nifti_image(dset,options) ;
00057
00058
00059
00060 nim->fname = malloc( strlen(fname)+16 ) ;
00061 nim->iname = malloc( strlen(fname)+16 ) ;
00062 strcpy(nim->fname,fname) ;
00063 strcpy(nim->iname,fname) ;
00064
00065
00066
00067 if( options.debug_level > 2 ) nifti_image_infodump(nim) ;
00068 nbl.bricks = (void **) malloc ( DSET_NVALS(dset) * sizeof(void*) ) ;
00069 nbl.nbricks = DSET_NVALS(dset) ;
00070 nbl.bsize = DSET_BRICK_BYTES(dset,0) ;
00071 for (ii = 0 ; ii < DSET_NVALS(dset) ; ii++ ) {
00072 nbl.bricks[ii] = DSET_ARRAY(dset,ii) ;
00073 }
00074
00075
00076
00077 nifti_set_afni_extension( dset , nim ) ;
00078
00079 nifti_image_write_bricks (nim, &nbl ) ;
00080 RETURN(1) ;
00081 }
00082
00083
00084
00085 nifti_image * populate_nifti_image(THD_3dim_dataset *dset, niftiwr_opts_t options)
00086 {
00087 int nparam, type0 , ii , jj, val;
00088 int nif_x_axnum, nif_y_axnum, nif_z_axnum ;
00089 int slast, sfirst ;
00090 int pattern_unknown = 0 ;
00091 nifti_image * nim ;
00092 char axcode[3], axsign[3] ;
00093 float axstep[3] , axstart[3] ;
00094 int axnum[3] ;
00095 float fac0 ;
00096 float dumqx, dumqy, dumqz, dumdx, dumdy, dumdz ;
00097 float pixdimfac[4] ;
00098 float odd_del, even_del, tmp_float ;
00099 int even_parity_sign = 0 ;
00100
00101 ENTRY("populate_nifti_image") ;
00102
00103
00104 nim = (nifti_image *) calloc( 1 , sizeof(nifti_image) ) ;
00105 if( !nim ) {
00106 fprintf(stderr, "** ERROR: failed to allocate nifti image\n");
00107 RETURN(0) ;
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 if (dset->dblk->nvals > 1) {
00123 STATUS("4D dataset") ;
00124 nim->ndim = (dset->taxis != NULL) ? 4 : 5 ;
00125
00126
00127
00128 type0 = DSET_BRICK_TYPE(dset,0) ;
00129 fac0 = DSET_BRICK_FACTOR(dset,0) ;
00130
00131 for( ii=1 ; ii < DSET_NVALS(dset) ; ii++ ){
00132 if( DSET_BRICK_TYPE(dset,ii) != type0){
00133 fprintf(stderr,
00134 "** ERROR: CANNOT WRITE NIFTI FILE; BRICK DATA TYPES NOT CONSISTENT\n") ;
00135 RETURN(0);
00136 } else if( DSET_BRICK_FACTOR(dset,ii) != fac0) {
00137 fprintf(stderr,
00138 "** ERROR: CANNOT WRITE NIFTI FILE; BRICK FACTORS NOT CONSISTENT\n") ;
00139 fprintf(stderr,
00140 "RICH HAMMETT SHOULD FIX THIS REAL SOON NOW\n") ;
00141 RETURN(0);
00142 }
00143 }
00144 } else {
00145 STATUS("3D dataset") ;
00146 if( options.debug_level > 1 ) fprintf(stderr,"ONLY ONE BRICK!!!\n") ;
00147 type0 = DSET_BRICK_TYPE(dset,0);
00148 fac0 = DSET_BRICK_FACTOR(dset,0) ;
00149 if (ISFUNC(dset)) {
00150 STATUS("functional dataset") ;
00151 if( options.debug_level > 1 )
00152 fprintf(stderr,"ONLY ONE BRICK, AND IT'S FUNCTIONAL!!!\n") ;
00153 nim->intent_code = DSET_BRICK_STATCODE(dset,0);
00154 if (nim->intent_code < 0) nim->intent_code = dset->func_type ;
00155 if (nim->intent_code < 0) nim->intent_code = NIFTI_INTENT_NONE ;
00156 if( options.debug_level > 1 )
00157 fprintf(stderr,"ONLY ONE BRICK, AND ITS FUNCTIONAL STAT CODE IS %d !!!\n",nim->intent_code) ;
00158 if(PRINT_TRACING){
00159 char str[256]; sprintf(str,"intent_code = %d",nim->intent_code);STATUS(str);
00160 }
00161 if (nim->intent_code > -1) {
00162 nparam = FUNC_need_stat_aux[nim->intent_code];
00163 if (nparam >= 1) nim->intent_p1 = DSET_BRICK_STATPAR(dset,0,1);
00164 if (nparam >= 2) nim->intent_p2 = DSET_BRICK_STATPAR(dset,0,2);
00165 if (nparam == 3) nim->intent_p3 = DSET_BRICK_STATPAR(dset,0,3);
00166 }
00167 }
00168 if (dset->daxes->nzz > 1) {
00169 nim->ndim = 3 ;
00170 } else if (dset->daxes->nyy > 1) {
00171 nim->ndim = 2 ;
00172 } else {
00173 nim->ndim = 1;
00174 }
00175 }
00176
00177
00178
00179
00180 STATUS("set datatype") ;
00181 switch(type0) {
00182 case MRI_byte:
00183 nim->datatype = DT_UNSIGNED_CHAR;
00184 nim->nbyper = 1 ;
00185 break;
00186 case MRI_short:
00187 nim->datatype = DT_SIGNED_SHORT;
00188 nim->nbyper = 2 ;
00189 break;
00190 case MRI_int:
00191 nim->datatype = DT_SIGNED_INT;
00192 nim->nbyper = 4 ;
00193 break;
00194 case MRI_float:
00195 nim->datatype = DT_FLOAT;
00196 nim->nbyper = 4 ;
00197 break;
00198 case MRI_double:
00199 nim->datatype = DT_DOUBLE;
00200 nim->nbyper = 8 ;
00201 break;
00202 case MRI_complex:
00203 nim->datatype = DT_COMPLEX;
00204 nim->nbyper = 8 ;
00205 break;
00206 case MRI_rgb:
00207 nim->datatype = DT_RGB24;
00208 nim->nbyper = 3 ;
00209 break;
00210 case MRI_rgba:
00211 fprintf(stderr,
00212 "** ERROR: Can't write NIFTI file since dataset is RGBA: %s\n",
00213 options.infile_name) ;
00214 RETURN(0) ;
00215 break;
00216 default:
00217 fprintf(stderr,
00218 "** ERROR: Can't write NIFTI file since datatype is unknown: %s\n",
00219 options.infile_name) ;
00220 RETURN(0) ;
00221 break;
00222 }
00223
00224
00225
00226 nim->scl_slope = fac0 ;
00227 nim->scl_inter = 0 ;
00228
00229
00230
00231 STATUS("set orientation") ;
00232
00233 axcode[0] = ORIENT_xyz[ dset->daxes->xxorient ] ; axnum[0] = dset->daxes->nxx ;
00234 axcode[1] = ORIENT_xyz[ dset->daxes->yyorient ] ; axnum[1] = dset->daxes->nyy ;
00235 axcode[2] = ORIENT_xyz[ dset->daxes->zzorient ] ; axnum[2] = dset->daxes->nzz ;
00236
00237 axsign[0] = ORIENT_sign[ dset->daxes->xxorient ] ;
00238 axsign[1] = ORIENT_sign[ dset->daxes->yyorient ] ;
00239 axsign[2] = ORIENT_sign[ dset->daxes->zzorient ] ;
00240
00241 axstep[0] = dset->daxes->xxdel ; axstart[0] = dset->daxes->xxorg ;
00242 axstep[1] = dset->daxes->yydel ; axstart[1] = dset->daxes->yyorg ;
00243 axstep[2] = dset->daxes->zzdel ; axstart[2] = dset->daxes->zzorg ;
00244
00245 for (ii = 0 ; ii < 3 ; ii++ ) {
00246 if (axcode[ii] == 'x') {
00247 nif_x_axnum = ii ;
00248 } else if (axcode[ii] == 'y') {
00249 nif_y_axnum = ii ;
00250 } else nif_z_axnum = ii ;
00251 }
00252
00253 nim->qto_xyz.m[0][0] = nim->qto_xyz.m[0][1] = nim->qto_xyz.m[0][2] =
00254 nim->qto_xyz.m[1][0] = nim->qto_xyz.m[1][1] = nim->qto_xyz.m[1][2] =
00255 nim->qto_xyz.m[2][0] = nim->qto_xyz.m[2][1] = nim->qto_xyz.m[2][2] = 0.0 ;
00256
00257
00258
00259 nim->dx = nim->pixdim[1] = fabs ( axstep[0] ) ;
00260 nim->dy = nim->pixdim[2] = fabs ( axstep[1] ) ;
00261 nim->dz = nim->pixdim[3] = fabs ( axstep[2] ) ;
00262
00263 nim->du = nim->pixdim[5] = 0 ;
00264 nim->dv = nim->pixdim[6] = 0 ;
00265 nim->dw = nim->pixdim[7] = 0 ;
00266
00267 #if 0
00268 val = (axsign[nif_x_axnum] == '+') ? -1 : 1 ;
00269 nim->qto_xyz.m[0][nif_x_axnum] = val * nim->pixdim[nif_x_axnum + 1];
00270 val = (axsign[nif_y_axnum] == '+') ? -1 : 1 ;
00271 nim->qto_xyz.m[1][nif_y_axnum] = val * nim->pixdim[nif_y_axnum + 1];
00272 val = (axsign[nif_x_axnum] == '-') ? -1 : 1 ;
00273 nim->qto_xyz.m[2][nif_z_axnum] = val * nim->pixdim[nif_z_axnum + 1];
00274 #else
00275 nim->qto_xyz.m[0][nif_x_axnum] = - axstep[nif_x_axnum];
00276 nim->qto_xyz.m[1][nif_y_axnum] = - axstep[nif_y_axnum];
00277 nim->qto_xyz.m[2][nif_z_axnum] = axstep[nif_z_axnum];
00278 #endif
00279
00280
00281
00282 #if 0
00283 nim->qoffset_x = axstart[nif_x_axnum] ;
00284 if (axsign[nif_x_axnum] == '+') nim->qoffset_x = - nim->qoffset_x ;
00285 nim->qoffset_y = axstart[nif_y_axnum];
00286 if (axsign[nif_y_axnum] == '+') nim->qoffset_y = - nim->qoffset_y ;
00287 nim->qoffset_z = axstart[nif_z_axnum];
00288 if (axsign[nif_z_axnum] == '-') nim->qoffset_z = - nim->qoffset_z ;
00289 #endif
00290
00291 nim->qoffset_x = -axstart[nif_x_axnum] ;
00292 nim->qoffset_y = -axstart[nif_y_axnum];
00293 nim->qoffset_z = axstart[nif_z_axnum];
00294
00295 #if 0
00296 nim->qoffset_x = -axstart[0] ;
00297 nim->qoffset_y = -axstart[1];
00298 nim->qoffset_z = axstart[2];
00299 #endif
00300
00301 nim->qto_xyz.m[0][3] = nim->qoffset_x ;
00302 nim->qto_xyz.m[1][3] = nim->qoffset_y ;
00303 nim->qto_xyz.m[2][3] = nim->qoffset_z ;
00304
00305
00306
00307 STATUS("set quaternion") ;
00308
00309 nifti_mat44_to_quatern( nim->qto_xyz , &nim->quatern_b, &nim->quatern_c, &nim->quatern_d,
00310 &dumqx, &dumqy, &dumqz, &dumdx, &dumdy, &dumdz, &nim->qfac ) ;
00311
00312
00313
00314
00315
00316 for ( ii = 0 ; ii < 3 ; ii++ ) {
00317 for ( jj = 0 ; jj < 4 ; jj++ ) {
00318 nim->sto_xyz.m[ii][jj] = nim->qto_xyz.m[ii][jj] ;
00319 }
00320 }
00321
00322
00323
00324 if( options.debug_level > 2 )
00325 fprintf(stderr,"++ Quaternion check:\n"
00326 "%f , %f\n %f , %f\n %f , %f\n %f , %f\n %f , %f\n %f , %f\n; %f\n",
00327 nim->qoffset_x, dumqx , nim->qoffset_y, dumqy , nim->qoffset_z, dumqz ,
00328 nim->dx, dumdx , nim->dy, dumdy , nim->dz, dumdz, nim->qfac ) ;
00329
00330
00331
00332 nim->qto_ijk = nifti_mat44_inverse( nim->qto_xyz ) ;
00333
00334
00335
00336 nim->nt = nim->nu = nim->nv = nim->nw = 1 ;
00337 nim->nx = axnum[0] ;
00338 nim->ny = axnum[1] ;
00339 nim->nz = axnum[2] ;
00340
00341 if (dset->taxis == NULL) {
00342 nim->nu = DSET_NVALS(dset) ;
00343 } else {
00344 nim->nt = DSET_NUM_TIMES(dset) ;
00345 }
00346
00347 if ( nim->nt > 1){
00348 float TR = dset->taxis->ttdel ;
00349 if( DSET_TIMEUNITS(dset) == UNITS_MSEC_TYPE ) TR *= 0.001;
00350 nim->dt = nim->pixdim[4] = TR ;
00351 }
00352
00353 nim->dim[0] = nim->ndim;
00354 nim->dim[1] = nim->nx;
00355 nim->dim[2] = nim->ny;
00356 nim->dim[3] = nim->nz;
00357 nim->dim[4] = nim->nt;
00358 nim->dim[5] = nim->nu;
00359 nim->dim[6] = nim->nv;
00360 nim->dim[7] = nim->nw;
00361
00362 nim->nvox = nim->nx * nim->ny * nim->nz * nim->nt
00363 * nim->nu * nim->nv * nim->nw ;
00364
00365
00366
00367 nim->freq_dim = nim->phase_dim = 0 ;
00368 if (dset->taxis != NULL) {
00369 nim->slice_dim = 3 ;
00370 nim->slice_duration = 0 ;
00371 nim->slice_start = 0 ;
00372 nim->slice_end = nim->nz - 1;
00373 nim->toffset = DSET_TIMEORIGIN(dset);
00374
00375
00376
00377
00378
00379
00380
00381 if (DSET_NUM_TTOFF(dset) > 0 ) {
00382
00383
00384 #define MYEPSILON 0.00001
00385 #define MYFPEQ(a, b) (fabs((a) - (b)) < MYEPSILON)
00386
00387 for (ii = 0 ; ii < nim->nz ; ii++ ) {
00388 if (!MYFPEQ(dset->taxis->toff_sl[ii],0.0)) break ;
00389 }
00390 sfirst = ii ;
00391 for (ii = nim->nz - 1 ; ii >= sfirst ; ii-- ) {
00392 if (!MYFPEQ(dset->taxis->toff_sl[ii],0.0)) break ;
00393 }
00394 slast = ii ;
00395
00396 if (slast == sfirst) {
00397
00398 pattern_unknown = 1 ;
00399 } else {
00400
00401
00402
00403
00404 if ( slast - sfirst == 1 ) {
00405 if (dset->taxis->toff_sl[slast] > dset->taxis->toff_sl[sfirst] ) {
00406 nim->slice_code = NIFTI_SLICE_SEQ_INC ;
00407 } else {
00408 nim->slice_code = NIFTI_SLICE_SEQ_DEC ;
00409 }
00410 } else {
00411
00412
00413
00414
00415
00416 odd_del = dset->taxis->toff_sl[sfirst + 1] -
00417 dset->taxis->toff_sl[sfirst] ;
00418 even_del = dset->taxis->toff_sl[sfirst + 2] -
00419 dset->taxis->toff_sl[sfirst + 1];
00420 for (ii = sfirst + 2 ; ii < slast - 1 ; ii += 2 ) {
00421 if (MYFPEQ(odd_del, dset->taxis->toff_sl[ii + 1] - dset->taxis->toff_sl[ii])) {
00422 if (MYFPEQ(even_del, dset->taxis->toff_sl[ii + 2] - dset->taxis->toff_sl[ii + 1])) {
00423 continue;
00424 }
00425 }
00426 pattern_unknown = 1 ;
00427 break ;
00428 }
00429
00430 if (ii == slast - 1 ) {
00431 if (!MYFPEQ(odd_del, dset->taxis->toff_sl[ii + 1] - dset->taxis->toff_sl[ii])) {
00432 pattern_unknown = 1 ;
00433 }
00434 } else {
00435 tmp_float = (dset->taxis->toff_sl[ii] - dset->taxis->toff_sl[ii - 1]) / odd_del ;
00436 even_parity_sign = tmp_float / fabs (tmp_float) ;
00437 }
00438
00439
00440
00441 if (!pattern_unknown ) {
00442 if (MYFPEQ(odd_del, even_del)) {
00443 if (odd_del > 0) nim->slice_code = NIFTI_SLICE_SEQ_INC ;
00444 else nim->slice_code = NIFTI_SLICE_SEQ_INC ;
00445 } else {
00446
00447
00448
00449
00450
00451
00452 if ((odd_del * even_del < 0 ) && (even_parity_sign != -1)) {
00453 if (odd_del + even_del > 0 ) {
00454 nim->slice_code = NIFTI_SLICE_ALT_INC ;
00455 } else {
00456 if (odd_del + even_del < 0 ) {
00457 nim->slice_code = NIFTI_SLICE_ALT_DEC ;
00458 } else {
00459 pattern_unknown = 1 ;
00460 }
00461 }
00462 } else {
00463 pattern_unknown = 1 ;
00464 }
00465 }
00466 }
00467 }
00468 }
00469 } else {
00470 pattern_unknown = 1 ;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 if (!pattern_unknown ) {
00485 switch (nim->slice_code) {
00486 case NIFTI_SLICE_SEQ_INC:
00487 nim->slice_duration = odd_del ;
00488 if (sfirst > 0) sfirst-- ;
00489 break ;
00490 case NIFTI_SLICE_ALT_INC:
00491 nim->slice_duration = fabs (odd_del + even_del ) ;
00492 if (sfirst > 0) sfirst-- ;
00493 break ;
00494 case NIFTI_SLICE_SEQ_DEC:
00495 nim->slice_duration = fabs (odd_del) ;
00496 if (slast < nim->nz - 1) slast++ ;
00497 break ;
00498 case NIFTI_SLICE_ALT_DEC:
00499 nim->slice_duration = fabs (odd_del + even_del ) ;
00500 if (slast < nim->nz - 1) slast++ ;
00501 break ;
00502 default:
00503 fprintf(stderr,
00504 "++ ERROR: CANNOT WRITE NIFTI FILE; LOGIC BORKED IN SLICE TIMING\n") ;
00505 fprintf(stderr, "RICH HAMMETT SHOULD FIX THIS REAL SOON NOW\n") ;
00506 RETURN(0);
00507 }
00508
00509 nim->slice_start = sfirst ;
00510 nim->slice_end = slast ;
00511
00512 } else {
00513 nim->slice_code = NIFTI_SLICE_UNKNOWN ;
00514 nim->slice_start = 0 ;
00515 nim->slice_end = 0 ;
00516 }
00517
00518 nim->time_units = NIFTI_UNITS_SEC ;
00519
00520 } else {
00521 nim->slice_dim = 0 ;
00522 nim->time_units = NIFTI_UNITS_UNKNOWN ;
00523 }
00524
00525
00526
00527 nim->byteorder = nifti_short_order() ;
00528
00529
00530
00531 if ( dset->view_type == VIEW_TALAIRACH_TYPE ) {
00532 nim->qform_code = NIFTI_XFORM_TALAIRACH ;
00533 } else {
00534 nim->qform_code = NIFTI_XFORM_SCANNER_ANAT ;
00535 }
00536 nim->sform_code = nim->qform_code ;
00537
00538
00539
00540
00541 nim->cal_min = nim->cal_max = 0 ;
00542 nim->nifti_type = 1 ;
00543 nim->xyz_units = NIFTI_UNITS_MM ;
00544 nim->num_ext = 0;
00545 nim->ext_list = NULL ;
00546 nim->iname_offset = 352 ;
00547 nim->data = NULL ;
00548
00549 RETURN(nim) ;
00550 }
00551
00552
00553
00554
00555 static char *badlist[] = {
00556 "IDCODE_STRING" ,
00557 "DATASET_RANK" ,
00558 "DATASET_DIMENSIONS" ,
00559 "TYPESTRING" ,
00560 "SCENE_DATA" ,
00561 "ORIENT_SPECIFIC" ,
00562 "ORIGIN" ,
00563 "DELTA" ,
00564 "TAXIS_NUMS" ,
00565 "TAXIS_FLOATS" ,
00566 "TAXIS_OFFSETS" ,
00567 "BYTEORDER_STRING" ,
00568 "BRICK_TYPES" ,
00569 "BRICK_FLOAT_FACS" ,
00570 "STAT_AUX" ,
00571 "LABEL_1" ,
00572 "LABEL_2" ,
00573 "DATASET_NAME" ,
00574 NULL } ;
00575
00576
00577
00578
00579
00580
00581
00582
00583 void nifti_set_afni_extension( THD_3dim_dataset *dset , nifti_image *nim )
00584 {
00585 THD_datablock *blk ;
00586 NI_group *ngr ;
00587 NI_element *nel ;
00588 NI_stream ns ;
00589 char *rhs , buf[128] ;
00590 int ii,bb , npart,*bpart ;
00591
00592 if( nim == NULL ) return ;
00593 if( AFNI_yesenv("AFNI_NIFTI_NOEXT") ) return ;
00594
00595
00596
00597 ngr = THD_nimlize_dsetatr( dset ) ;
00598 if( ngr == NULL ) return ;
00599 NI_rename_group( ngr , "AFNI_attributes" ) ;
00600
00601
00602
00603 sprintf(buf,"%d,%d,%d,%d,%d,%d" ,
00604 nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->datatype ) ;
00605 NI_set_attribute( ngr , "NIfTI_nums" , buf ) ;
00606
00607
00608
00609
00610 npart = ngr->part_num ;
00611 bpart = (int *)calloc(sizeof(int),npart) ;
00612 for( ii=0 ; ii < npart ; ii++ ){
00613 if( ngr->part_typ[ii] != NI_ELEMENT_TYPE ) continue ;
00614 nel = (NI_element *) ngr->part[ii] ;
00615 if( strcmp(nel->name,"AFNI_atr") != 0 ) continue ;
00616 rhs = NI_get_attribute( nel , "AFNI_name" ) ;
00617 if( rhs == NULL ) continue ;
00618
00619 for( bb=0 ; badlist[bb] != NULL ; bb++ )
00620 if( strcmp(rhs,badlist[bb]) == 0 ){ bpart[ii] = 1; break; }
00621 }
00622
00623
00624
00625 for( ii=npart-1 ; ii >= 0 ; ii-- ){
00626 if( bpart[ii] )
00627 NI_remove_from_group( ngr , ngr->part[ii] ) ;
00628 }
00629 free((void *)bpart) ;
00630 if( ngr->part_num <= 0 ){ NI_free_element(ngr); return; }
00631
00632
00633
00634 ns = NI_stream_open( "str:" , "w" ) ;
00635 NI_stream_writestring( ns , "<?xml version='1.0' ?>\n" ) ;
00636 NI_write_element( ns , ngr , NI_TEXT_MODE ) ;
00637 rhs = NI_stream_getbuf( ns ) ;
00638
00639
00640
00641 nifti_add_extension( nim , rhs , strlen(rhs)+1 , NIFTI_ECODE_AFNI ) ;
00642
00643 NI_stream_close(ns) ;
00644 NI_free_element(ngr) ;
00645 return ;
00646 }