Writing nibabel Nifti1Image objects into bytes in memory instead of on disk

I would like to do the opposite of the use-case mentioned in this thread: https://mail.python.org/pipermail/neuroimaging/2017-February/001346.html

That is, I would like to take a nibabel Nifti1Image object in and get an object in memory that holds the bytes that would have been saved to disk upon calling to to_filename, but without saving to disk.

Does anyone know how to do that?

For a bit more context, I am interested in using the S3FS library to read and write nifti files through direct interaction with AWS S3. I’ve figured out reading, based on that thread I mentioned above:

import gzip
import s3fs
from io import BytesIO
from nibabel import FileHolder, Nifti1Image

fname = 'bucket_name/full/path/to/file_name.nii.gz'
fs = s3fs.S3FileSystem()
with fs.open(fname) as f:
    zz = gzip.open(f)
    rr = zz.read()
    bb = BytesIO(rr)
    fh = FileHolder(fileobj=bb)
    img = Nifti1Image.from_file_map({'header': fh, 'image': fh})

But would now like to go in the opposite direction.

I know @effigies had started to work on this in https://github.com/nipy/nibabel/pull/644, and though that’s not yet merged you should be able to use a few lines of code from it for your purposes:

bio = BytesIO()
file_map = img.make_file_map({'image': bio, 'header': bio})
img.to_file_map(file_map)
data = bio.getvalue()

Hope that helps! :slight_smile:

4 Likes

And if you want it zipped as well:

bio = io.BytesIO()
zz = gzip.GzipFile(fileobj=bio, mode='w')
file_map = img.make_file_map({'image': zz, 'header': zz})
img.to_file_map(file_map)
data = bio.getvalue()
2 Likes

Beautiful. Thank you both!

Here is the whole functioning thing, including a rudimentary round-trip test: https://gist.github.com/arokem/423d915e157b659d37f4aded2747d2b3

2 Likes