|
9 | 9 | import random
|
10 | 10 | import re
|
11 | 11 | import shutil
|
| 12 | +import gzip |
12 | 13 | import sys
|
13 | 14 | from types import ModuleType
|
14 | 15 | from typing import TYPE_CHECKING, Any, List, Optional, cast
|
@@ -630,6 +631,19 @@ def convert(
|
630 | 631 | item_dicoms, prefix, with_prov, bids_options, tmpdir, dcmconfig
|
631 | 632 | )
|
632 | 633 |
|
| 634 | + # try to handle compression failures from dcm2niix |
| 635 | + if outtype == 'nii.gz': |
| 636 | + converted_files = res.outputs.converted_files |
| 637 | + if not isinstance(converted_files, list): |
| 638 | + converted_files = [converted_files] |
| 639 | + uncompressed = [x for x in converted_files if x.endswith('.nii')] |
| 640 | + if len(uncompressed) > 0: |
| 641 | + lgr.warning("Conversion returned uncompressed nifti (>4GB?) - " |
| 642 | + "trying to salvage by recompressing ourselves. " |
| 643 | + "This might take a while ") |
| 644 | + if not recompress_failed(uncompressed): |
| 645 | + raise RuntimeError("Error compressing nifti") |
| 646 | + |
633 | 647 | bids_outfiles = save_converted_files(
|
634 | 648 | res,
|
635 | 649 | item_dicoms,
|
@@ -1099,3 +1113,35 @@ def bvals_are_zero(bval_file: str | list) -> bool:
|
1099 | 1113 |
|
1100 | 1114 | bvals_unique = set(float(b) for b in bvals)
|
1101 | 1115 | return bvals_unique == {0.0} or bvals_unique == {5.0}
|
| 1116 | + |
| 1117 | + |
| 1118 | +def recompress_failed(niftis: list) -> bool: |
| 1119 | + """Tries to recompress nifti files with built-in gzip module |
| 1120 | +
|
| 1121 | + Parameters |
| 1122 | + ---------- |
| 1123 | + niftis : list |
| 1124 | + list of nifti file paths |
| 1125 | +
|
| 1126 | + Returns |
| 1127 | + ------- |
| 1128 | + True if all nifits were sucessfully compressed. False otherwise. |
| 1129 | + """ |
| 1130 | + |
| 1131 | + from nibabel import load as nb_load |
| 1132 | + from nibabel.filebasedimages import ImageFileError |
| 1133 | + |
| 1134 | + for nifti in niftis: |
| 1135 | + try: |
| 1136 | + img = nb_load(nifti) |
| 1137 | + _ = img.get_fdata() # read everything to catch truncated/corrupted files |
| 1138 | + with open(nifti, 'rb') as f_in: |
| 1139 | + with gzip.open(nifti + '.gz', 'wb', compresslevel=6) as f_out: |
| 1140 | + shutil.copyfileobj(f_in, f_out) |
| 1141 | + # nipype results still carry uncompressed file names and they will |
| 1142 | + # be renamed to '.nii.gz' later |
| 1143 | + os.rename(nifti + '.gz', nifti) |
| 1144 | + except (OSError, ImageFileError, gzip.zlib.error): |
| 1145 | + return False |
| 1146 | + |
| 1147 | + return True |
0 commit comments