123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646 |
- function headerInfo = nhdr_nrrd_write(nrrdFileName, headerInfo, bWriteData)
- [path_main_header, ~, fext] = fileparts(nrrdFileName);
- if isfield(headerInfo, 'datafiles')
- assert(strcmpi(fext, '.nhdr'), sprintf('Invalid filename extension ''%s''. A detached nrrd header (headerInfo structure contains ''datafiles'' field) should have extension ''.nhdr''.\n',fext));
- else
- assert(strcmpi(fext, '.nrrd'), sprintf('Invalid filename extension ''%s''. A standalone nrrd file (no ''datafiles'' field in headerInfo structure) should have extension ''.nrrd''.\n',fext));
- end
- header_fnames = fieldnames(headerInfo);
- fnames_parsed = false(1,length(header_fnames));
- if isfield(headerInfo, 'sizes')
- if isfield(headerInfo, 'data')
- assert(nrrd_size_check(size(headerInfo.data), headerInfo.sizes),...
- sprintf('Sizes mismatch: [%s] in headerInfo structure is not compatible with the size of the data array [%s].\n',...
- sprintf('%d ',headerInfo.sizes), sprintf('%d ',size(headerInfo.data)) ));
- end
- else
- assert( isfield(headerInfo, 'data'), sprintf('Missing required field ''sizes'' in headerInfo structure, cannot be deduced from data because no data was provided.\n'));
- headerInfo.sizes = size(headerInfo.data);
- end
- if isfield(headerInfo, 'dimension')
- assert( isequal(headerInfo.dimension, length(headerInfo.sizes)), sprintf('Dimension mismatch: %d in headerInfo structure is not compatible with detected data size [%s].\n',...
- headerInfo.dimension, sprintf('%d ', headerInfo.sizes)));
- else
- headerInfo.dimension = length(headerInfo.sizes);
- end
- if isfield(headerInfo, 'type')
- matlabdatatype = nrrd_getMatlabDataType(headerInfo.type);
- if isfield(headerInfo, 'data')
- assert( isequal(class(headerInfo.data), matlabdatatype), ...
- sprintf('Type mismatch: %s in headerInfo structure is not compatible with the Matlab type of the data array (%s).\nYou may want to look at nrrd_getMatlabDataType and at Matlab''s cast functions.',headerInfo.type, class(headerInfo.data)));
- end
- else
- assert( isfield(headerInfo, 'data'), sprintf('Missing required field ''type'' in headerInfo structure, cannot be deduced from data because no data was provided.\n'));
- headerInfo.type = get_nrrd_datatype(class(headerInfo.data));
- end
- if ~isfield(headerInfo, 'encoding')
- headerInfo.encoding = 'raw';
- end
- [~,~,endian] = computer();
- if (isequal(endian, 'B'))
- headerInfo.endian = 'big';
- else
- headerInfo.endian = 'little';
- end
-
- fidw = fopen( nrrdFileName, 'w');
- if fidw == -1
- error('nhdr_nrrd_writer: could not open file %s.\n',nrrdFileName);
- end
- try
-
- fprintf( fidw, 'NRRD0005\n' );
- fprintf( fidw, '# Complete NRRD file format specification at:\n' );
- fprintf( fidw, '# http://teem.sourceforge.net/nrrd/format.html\n' );
- if isfield(headerInfo,'content')
- fprintf( fidw, 'content: %s\n', headerInfo.content);
- fnames_parsed(strcmpi('content', header_fnames)) = true;
- end
- fprintf( fidw, 'type: %s\n', headerInfo.type );
- fnames_parsed(strcmpi('type', header_fnames)) = true;
- fprintf( fidw, 'encoding: %s\n', headerInfo.encoding);
- fnames_parsed(strcmpi('encoding', header_fnames)) = true;
- fprintf( fidw, 'dimension: %d\n', headerInfo.dimension );
- fnames_parsed(strcmpi('dimension', header_fnames)) = true;
- fprintf( fidw, 'sizes: ' );
- for iI=1:length( headerInfo.sizes )
- fprintf( fidw, '%d', headerInfo.sizes(iI) );
- if ( iI~=length( headerInfo.sizes ) )
- fprintf( fidw, ' ' );
- end
- end
- fprintf( fidw, '\n' );
- fnames_parsed(strcmpi('sizes', header_fnames)) = true;
- fprintf( fidw, 'endian: %s\n', headerInfo.endian );
- fnames_parsed(strcmpi('endian', header_fnames)) = true;
-
-
-
- define_orientation = 0;
- if isfield(headerInfo,'space')
- fprintf(fidw, 'space: %s\n', headerInfo.space );
- fnames_parsed(strcmpi('space', header_fnames)) = true;
- define_orientation = 1;
- num_sp_dim = nrrd_getSpaceDimensions(headerInfo.space);
- elseif isfield (headerInfo,'spacedimension')
- fprintf(fidw, 'space dimension: %d\n', headerInfo.spacedimension);
- fnames_parsed(strcmpi('spacedimension', header_fnames)) = true;
- define_orientation = 1;
- num_sp_dim = headerInfo.spacedimension;
- end
-
- if isfield(headerInfo,'space') && isfield(headerInfo, 'spacedimension')
- error('The always optional fields ''space'' and ''spacedimension'' defining orientation cannot be specified simultaneously in headerInfo structure');
- end
-
- if define_orientation
-
-
-
- assert(num_sp_dim>=3, sprintf('Number of space dimensions should be at least 3 in current nrrd format, detected %d instead in headerInfo structure.\n',num_sp_dim));
-
-
- if ~isfield(headerInfo, 'spacedirections')
- error('Missing field in headerInfo structure: spacedirections should always be specified if orientation is defined via ''space'' or ''space directions'' ');
- end
-
- assert(iscell(headerInfo.spacedirections), ...
- ['spacedirections field in headerInfo should be a cell array of ' ...
- 'strings for code compatibility, e.g. {''(1,0,0)'' ''(0,2,0.1)'' ''none'' ''(0.1,0.1,1.1)''}' ...
- ' for 3 world space dimensions.'])
-
- for i = 1:length(headerInfo.spacedirections)
- none_match = regexp(headerInfo.spacedirections{i}, 'none', 'match');
- if ~isempty(none_match)
-
- if ~strcmpi(headerInfo.spacedirections{i}, 'none')
- fprintf(['nhdr_nrrd_write WARNING: detected %s instead of ' ...
- 'expected none in header.spacedirections{%d}.\n Wrote clean version to output file(s).\n'],...
- headerInfo.spacedirections{i}, i)
- end
- headerInfo.spacedirections{i} = 'none';
- else
-
- btw_parentheses = headerInfo.spacedirections{i}(1) == '(' ...
- && headerInfo.spacedirections{i}(end) == ')';
- if ~btw_parentheses
- fprintf(['nhdr_nrrd_write WARNING: space vector in header.spacedirections{%d} ' ...
- 'should contain comma-separated values enclosed in single parentheses.\n ' ...
- 'At least one parenthesis missing here. Wrote clean version to output file(s).\n'],...
- i)
- end
- headerInfo.spacedirections{i} = ['(' regexprep(headerInfo.spacedirections{i}, '[()]', ''), ')'];
- end
- end
- spacedir_str = strjoin(headerInfo.spacedirections, ' ');
-
- fprintf(fidw, 'space directions: %s\n', spacedir_str);
-
- fnames_parsed(strcmpi('spacedirections', header_fnames)) = true;
-
-
- SD_data = strrep(spacedir_str, 'none', '');
- SD_data = extractNumbersWithout(SD_data, {'(',')',',', '"', ''''});
- assert(length(SD_data) == num_sp_dim^2, sprintf('expected spacedirections field to contain %d numbers (square of %d, the world space dimension). Found %d instead.\nspacedirections should be a cell array of strings containing vectors of the form (dx,dy,dz) or none entries.\n',...
- num_sp_dim^2, num_sp_dim, length(SD_data)))
-
- if isfield(headerInfo, 'spacedirections_matrix')
- assert(isequal(headerInfo.spacedirections_matrix(:), SD_data(:)), ...
- sprintf('Numeric data in spacedirections and spacedirections_matrix fields of headerInfo do not match. They should contain %d identical numbers in the same order.\n', num_sp_dim^2))
- else
-
- headerInfo.spacedirections_matrix = reshape(SD_data(:), [num_sp_dim, num_sp_dim]);
- end
- fnames_parsed(strcmpi('spacedirections_matrix', header_fnames)) = true;
- end
-
-
-
-
-
- if isfield(headerInfo,'spaceorigin')
- if define_orientation
- so = headerInfo.spaceorigin;
- assert(length(so)==num_sp_dim, ...
- sprintf('Field ''spaceorigin'' in headerInfo structure expected vector with %d entries to match the defined orientation, detected %d entries instead.\n',num_sp_dim, length(so)));
- fprintf( fidw, 'space origin: (%f%s)\n', so(1), sprintf(',%f',so(2:end)) );
- fnames_parsed(strcmpi('spaceorigin', header_fnames)) = true;
- else
- error('Field ''spaceorigin'' in headerInfo structure cannot be specified if neither ''space'' nor ''spacedimension'' was specified.');
- end
- end
-
-
- if isfield(headerInfo,'measurementframe')
- if define_orientation
- mf = headerInfo.measurementframe;
- assert(size(mf,1)==num_sp_dim && size(mf,2)==num_sp_dim,...
- sprintf('Field ''measurementframe'' in headerInfo structure expected a %d-by-%d matrix to match the defined orientation, detected size [%s] instead.\n',...
- num_sp_dim, num_sp_dim, sprintf('%d ',size(mf))));
-
- fprintf( fidw, 'measurement frame:');
- for imf = 1:size(mf,2)
- fprintf(fidw,' (%f%s)', mf(1,imf), sprintf(',%f',mf(2:end,imf)));
- end
- fprintf(fidw, '\n');
- fnames_parsed(strcmpi('measurementframe', header_fnames)) = true;
- else
- error('Field ''measurementframe'' in headerInfo structure cannot be specified if neither ''space'' nor ''spacedimension'' were specified.');
- end
- end
-
-
- if isfield(headerInfo,'spaceunits')
- if define_orientation
- fprintf( fidw, 'space units: ' );
- for iI=1:length( headerInfo.spaceunits )
- fprintf( fidw, '\"%s\"', char(headerInfo.spaceunits(iI)) );
- if ( iI~=length( headerInfo.spaceunits ) )
- fprintf( fidw, ' ' );
- end
- end
- fprintf( fidw, '\n' );
- fnames_parsed(strcmpi('spaceunits', header_fnames)) = true;
- else
- error('Field ''spaceunits'' in headerInfo structure cannot be specified if neither ''space'' nor ''spacedimension'' were specified.');
- end
- end
-
-
-
-
-
- if isfield(headerInfo, 'kinds')
- assert(length(headerInfo.kinds)==headerInfo.dimension, sprintf('Detected %d kinds instead of expected nrrd dimension %d.\n',length(headerInfo.kinds), headerInfo.dimension));
- fprintf( fidw, 'kinds: ' );
- for iI=1:length( headerInfo.kinds )
- fprintf( fidw, '%s', headerInfo.kinds{iI} );
- if ( iI~=length( headerInfo.kinds ) )
- fprintf( fidw, ' ' );
- end
- end
- fprintf( fidw, '\n' );
- fnames_parsed(strcmpi('kinds', header_fnames)) = true;
- end
-
-
- if isfield(headerInfo, 'lineskip')
- assert(headerInfo.lineskip >= 0, sprintf('Field ''lineskip'' in headerInfo structure should be non-negative, detected %d.\n', headerInfo.lineskip));
- fprintf(fidw, 'lineskip: %d\n', headerInfo.lineskip);
- fnames_parsed(strcmpi('lineskip', header_fnames)) = true;
- end
-
-
- if isfield(headerInfo, 'byteskip')
- assert(headerInfo.byteskip >= -1, sprintf('Field ''byteskip'' should be -1 or a non-negative integer, detected %d.\n', headerInfo.byteskip));
- if headerInfo.byteskip == -1
- assert(strcmpi(headerInfo.encoding, 'raw'), sprintf('byte skip value of -1 is only valid with raw encoding.\n'));
- end
- fprintf(fidw, 'byteskip: %d\n', headerInfo.byteskip);
- fnames_parsed(strcmpi('byteskip', header_fnames)) = true;
- end
-
-
-
-
- if isfield(headerInfo, 'modality')
- fprintf( fidw, 'modality:=%s\n',headerInfo.modality);
- fnames_parsed( strcmpi('modality', header_fnames)) = true;
- end
-
-
- if isfield(headerInfo, 'bvalue')
- fprintf( fidw, 'DWMRI_b-value:=%9.8f\n', headerInfo.bvalue);
- fnames_parsed( strcmpi('bvalue', header_fnames)) = true;
- end
-
-
- if isfield(headerInfo, 'gradients')
- Ngrads = size(headerInfo.gradients, 1);
- for igrad = 1:Ngrads
- strprint = strcat('DWMRI_gradient_',sprintf('%04d',igrad-1)) ;
- strprint = [strprint,':='] ;
- strprint = [strprint, sprintf('%9.8f ', headerInfo.gradients(igrad,:))] ;
- fprintf(fidw,[strprint '\n']) ;
- end
- fnames_parsed(strcmpi('gradients', header_fnames)) = true;
-
- end
-
-
-
-
- if isfield(headerInfo, 'datafiles')
-
-
-
-
-
- if ischar(headerInfo.datafiles)
- headerInfo.datafiles = { headerInfo.datafiles};
- end
-
- if length(headerInfo.datafiles)==1
-
- fprintf(fidw, 'data file: %s\n',headerInfo.datafiles{1});
- else
-
-
- fprintf(fidw, 'data file: LIST\n');
- for i = 1:length(headerInfo.datafiles)
- fprintf(fidw,'%s\n', headerInfo.datafiles{i});
- end
- end
- fnames_parsed(strcmpi('datafiles', header_fnames)) = true;
- end
-
- catch me
- fclose(fidw);
- rethrow(me);
- end
- if bWriteData
-
- if isfield(headerInfo, 'datafiles')
-
-
-
- fclose(fidw);
-
- N_data_tot = prod(headerInfo.sizes);
-
-
- N_data_files = length(headerInfo.datafiles);
-
- assert(mod(N_data_tot, N_data_files)==0, sprintf('Number of detected data files (%d) does not divide total number of values contained in data %d obtained from prod(sizes=[%s]).\n',...
- N_data_files, N_data_tot, sprintf('%d ',headerInfo.sizes)));
-
- N_data_per_file = N_data_tot/N_data_files;
-
- for i = 1:N_data_files
-
-
- [~,fname_data,ext_data] = fileparts(headerInfo.datafiles{i});
-
- data_ind = (i-1)*N_data_per_file+1:i*N_data_per_file;
-
- if strcmpi(ext_data,'.nhdr')
-
- error('datafile %di/%d: nhdr file should not be used as detached data file.\n',i,length(headerInfo.datafiles));
-
- elseif strcmpi(ext_data, '.nrrd')
-
-
- assert(isfield(headerInfo, 'detached_header'), sprintf('Missing field ''detached_header'' in headerInfo structure.\nThis is only required for detached headers with data stored in detached data files of type nrrd.\nShould contain a Matlab structure describing the chunk of data stored in the detached nrrd file (the data field, if present, will be overwritten).\nIt is assumed that the header is identical for all detached nrrd data files.\n'));
-
-
- info_detached_data = headerInfo.detached_header;
- fnames_parsed(strcmpi('detached_header', header_fnames)) = true;
-
-
- info_detached_data.data = headerInfo.data(data_ind);
- info_detached_data.data = reshape(info_detached_data.data, info_detached_data.sizes);
-
-
- bWrite_Detached_Data = true;
- tmp_struct = nhdr_nrrd_write(fullfile(path_main_header, [fname_data, ext_data]), info_detached_data, bWrite_Detached_Data);
-
- else
-
-
- fid_data = fopen( fullfile(path_main_header, [fname_data, ext_data]), 'w');
- if( fid_data < 1 )
- error('Detached data file number %d/%d (%s) could not be opened.\n', i, N_data_files, headerInfo.datafiles{i});
- end
-
- try
- outtype = nrrd_getMatlabDataType(headerInfo.type);
- writeData(fid_data, headerInfo.data(data_ind), outtype, headerInfo.encoding);
- fclose(fid_data);
- catch me_detached
- fclose(fid_data);
- rethrow(me_detached);
- end
-
-
- end
-
- end
-
-
- else
-
-
- try
-
-
- fprintf(fidw, '\n');
- outtype = nrrd_getMatlabDataType(headerInfo.type);
- writeData(fidw, headerInfo.data, outtype, headerInfo.encoding);
- fclose(fidw);
- catch me_data
- fclose(fidw);
- rethrow(me_data);
- end
-
- end
-
- else
- fclose(fidw);
- end
- for i = 1:length(header_fnames)
- if ~fnames_parsed(i) && ~strcmpi(header_fnames{i},'data')
- fprintf('nhdr_nrrd_write WARNING: could not parse and write field %s from headerInfo structure.\n', header_fnames{i});
- end
- end
- end
- function iNrs = extractNumbersWithout( inputString, withoutTokens )
- auxStr = inputString;
- for iI=1:length( withoutTokens )
-
- auxStr = strrep( auxStr, withoutTokens{iI}, ' ' );
-
- end
- iNrs = sscanf( auxStr, '%f' );
- end
- function nrrddatatype = get_nrrd_datatype(matlab_metaType)
- switch (matlab_metaType)
- case {'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64',...
- 'uint64', 'double'}
- nrrddatatype = matlab_metaType;
-
- case {'single'}
- nrrddatatype = 'float';
-
- case {'block'}
- error('Data type ''block'' is currently not supported.\n');
-
- otherwise
- error('Unknown matlab datatype %s', matlab_metaType)
- end
- end
- function ok = writeData(fidIn, matrix, datatype, encoding)
- switch (encoding)
- case {'raw'}
-
- ok = fwrite(fidIn, matrix(:), datatype);
-
- case {'gzip', 'gz'}
-
-
- tmpBase = tempname(pwd);
- fidTmpRaw = fopen(tmpBase, 'w');
- assert(fidTmpRaw > 3, 'Could not open temporary file for GZIP compression');
- try
- fwrite(fidTmpRaw, matrix(:), datatype);
- fclose(fidTmpRaw);
- catch me
- fclose(fidTmpRaw);
- delete(tmpBase);
- rethrow(me);
- end
-
-
-
- tmpFile = [tmpBase '.gz'];
- try
- gzip(tmpBase);
- catch me
- delete(tmpBase);
- rethrow(me);
- end
- delete(tmpBase);
-
-
-
- fidTmpRaw = fopen(tmpFile, 'r');
- assert(fidTmpRaw > 3, 'Could not open temporary file for writing to nrrd file during gzip compression.');
- try
-
- tmp = fread(fidTmpRaw, Inf, 'uint8=>uint8');
- fclose(fidTmpRaw) ;
- catch me
- fclose(fidTmpRaw);
- delete(tmpFile);
- rethrow(me);
- end
-
-
- ok = fwrite(fidIn, tmp, 'uint8');
- delete (tmpFile);
- case {'text', 'txt', 'ascii'}
-
- ok = fprintf(fidIn,'%u ', matrix(:));
-
-
- otherwise
- error('Unsupported encoding %s', encoding)
- end
- end
- function sizesok = nrrd_size_check(matlab_size, nrrd_size)
- matlab_size = matlab_size(:)';
- nrrd_size = nrrd_size(:)';
- if length(nrrd_size)==1
- sizesok = prod(matlab_size)==nrrd_size;
- elseif length(nrrd_size)>=2
- ind_max = find(nrrd_size~=1,1,'last');
-
- if isempty(ind_max)
- ind_max = 2;
- else
- ind_max = max(2, ind_max);
- end
-
-
- sizesok = isequal(matlab_size, nrrd_size(1:ind_max));
- else
- error('Argument nrrd_size is an empty matrix');
- end
- end
|