Skip to content

ENH: Allow save-time passing of on-disk dtype to save functions #1083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions nibabel/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -989,23 +989,29 @@ def _get_fileholders(file_map):
"""
return file_map['header'], file_map['image']

def to_file_map(self, file_map=None):
def to_file_map(self, file_map=None, dtype=None):
""" Write image to `file_map` or contained ``self.file_map``

Parameters
----------
file_map : None or mapping, optional
files mapping. If None (default) use object's ``file_map``
attribute instead
dtype : dtype-like, optional
The on-disk data type to coerce the data array.
"""
if file_map is None:
file_map = self.file_map
data = np.asanyarray(self.dataobj)
self.update_header()
hdr = self._header
out_dtype = self.get_data_dtype()
# Store consumable values for later restore
offset = hdr.get_data_offset()
data_dtype = hdr.get_data_dtype()
# Override dtype conditionally
if dtype is not None:
hdr.set_data_dtype(out_dtype)
out_dtype = hdr.get_data_dtype()
# Scalars of slope, offset to get immutable values
slope = hdr['scl_slope'].item() if hdr.has_data_slope else np.nan
inter = hdr['scl_inter'].item() if hdr.has_data_intercept else np.nan
Expand Down Expand Up @@ -1045,6 +1051,7 @@ def to_file_map(self, file_map=None):
self.file_map = file_map
# Restore any changed consumable values
hdr.set_data_offset(offset)
hdr.set_data_dtype(data_dtype)
if hdr.has_data_slope:
hdr['scl_slope'] = slope
if hdr.has_data_intercept:
Expand Down
15 changes: 9 additions & 6 deletions nibabel/filebasedimages.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ def filespec_to_file_map(klass, filespec):
file_map[key] = FileHolder(filename=fname)
return file_map

def to_filename(self, filename):
def to_filename(self, filename, **kwargs):
""" Write image to files implied by filename string

Parameters
Expand All @@ -308,15 +308,17 @@ def to_filename(self, filename):
filename to which to save image. We will parse `filename`
with ``filespec_to_file_map`` to work out names for image,
header etc.
\*\*kwargs : keyword arguments
Keyword arguments to format-specific save

Returns
-------
None
"""
self.file_map = self.filespec_to_file_map(filename)
self.to_file_map()
self.to_file_map(**kwargs)

def to_file_map(self, file_map=None):
def to_file_map(self, file_map=None, **kwargs):
raise NotImplementedError

@classmethod
Expand Down Expand Up @@ -552,13 +554,14 @@ def from_bytes(klass, bytestring):
file_map = klass.make_file_map({'image': bio, 'header': bio})
return klass.from_file_map(file_map)

def to_bytes(self):
def to_bytes(self, **kwargs):
""" Return a ``bytes`` object with the contents of the file that would
be written if the image were saved.

Parameters
----------
None
\*\*kwargs : keyword arguments
Keyword arguments that may be passed to ``img.to_file_map()``

Returns
-------
Expand All @@ -569,5 +572,5 @@ def to_bytes(self):
raise NotImplementedError("to_bytes() is undefined for multi-file images")
bio = io.BytesIO()
file_map = self.make_file_map({'image': bio, 'header': bio})
self.to_file_map(file_map)
self.to_file_map(file_map, **kwargs)
return bio.getvalue()
8 changes: 5 additions & 3 deletions nibabel/loadsave.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def guessed_image_type(filename):
raise ImageFileError(f'Cannot work out file type of "{filename}"')


def save(img, filename):
def save(img, filename, **kwargs):
""" Save an image to file adapting format to `filename`

Parameters
Expand All @@ -139,6 +139,8 @@ def save(img, filename):
image to save
filename : str or os.PathLike
filename (often implying filenames) to which to save `img`.
\*\*kwargs : keyword arguments
Keyword arguments to format-specific save

Returns
-------
Expand All @@ -148,7 +150,7 @@ def save(img, filename):

# Save the type as expected
try:
img.to_filename(filename)
img.to_filename(filename, **kwargs)
except ImageFileError:
pass
else:
Expand Down Expand Up @@ -196,7 +198,7 @@ def save(img, filename):
# Here, we either have a klass or a converted image.
if converted is None:
converted = klass.from_image(img)
converted.to_filename(filename)
converted.to_filename(filename, **kwargs)


@deprecate_with_version('read_img_data deprecated. '
Expand Down