diff --git a/nibabel/gifti/parse_gifti_fast.py b/nibabel/gifti/parse_gifti_fast.py index de02f4c76b..f27e0725d6 100644 --- a/nibabel/gifti/parse_gifti_fast.py +++ b/nibabel/gifti/parse_gifti_fast.py @@ -33,43 +33,41 @@ class GiftiParseError(ExpatError): def read_data_block(encoding, endian, ordering, datatype, shape, data): """ Tries to unzip, decode, parse the funny string data """ - ord = array_index_order_codes.npcode[ordering] enclabel = gifti_encoding_codes.label[encoding] + dtype = data_type_codes.type[datatype] if enclabel == 'ASCII': # GIFTI_ENCODING_ASCII c = StringIO(data) - da = np.loadtxt(c) - da = da.astype(data_type_codes.type[datatype]) + da = np.loadtxt(c, dtype=dtype) return da # independent of the endianness - elif enclabel == 'B64BIN': - # GIFTI_ENCODING_B64BIN - dec = base64.b64decode(data.encode('ascii')) - dt = data_type_codes.type[datatype] - sh = tuple(shape) - newarr = np.frombuffer(dec, dtype=dt) - if len(newarr.shape) != len(sh): - newarr = newarr.reshape(sh, order=ord) - - elif enclabel == 'B64GZ': - # GIFTI_ENCODING_B64GZ - # convert to bytes array for python 3.2 - # http://www.diveintopython3.net/strings.html#byte-arrays - dec = base64.b64decode(data.encode('ascii')) - zdec = zlib.decompress(dec) - dt = data_type_codes.type[datatype] - sh = tuple(shape) - newarr = np.frombuffer(zdec, dtype=dt) - if len(newarr.shape) != len(sh): - newarr = newarr.reshape(sh, order=ord) - elif enclabel == 'External': # GIFTI_ENCODING_EXTBIN raise NotImplementedError("In what format are the external files?") - else: + elif enclabel not in ('B64BIN', 'B64GZ'): return 0 + # Numpy arrays created from bytes objects are read-only. + # Neither b64decode nor decompress will return bytearrays, and there + # are not equivalents to fobj.readinto to allow us to pass them, so + # there is not a simple way to avoid making copies. + # If this becomes a problem, we should write a decoding interface with + # a tunable chunk size. + dec = base64.b64decode(data.encode('ascii')) + if enclabel == 'B64BIN': + # GIFTI_ENCODING_B64BIN + buff = bytearray(dec) + else: + # GIFTI_ENCODING_B64GZ + buff = bytearray(zlib.decompress(dec)) + del dec + + sh = tuple(shape) + newarr = np.frombuffer(buff, dtype=dtype) + if len(newarr.shape) != len(sh): + newarr = newarr.reshape(sh, order=array_index_order_codes.npcode[ordering]) + # check if we need to byteswap required_byteorder = gifti_endian_codes.byteorder[endian] if (required_byteorder in ('big', 'little') and diff --git a/nibabel/gifti/tests/test_parse_gifti_fast.py b/nibabel/gifti/tests/test_parse_gifti_fast.py index 9adc03d8fd..726779d988 100644 --- a/nibabel/gifti/tests/test_parse_gifti_fast.py +++ b/nibabel/gifti/tests/test_parse_gifti_fast.py @@ -268,6 +268,13 @@ def test_readwritedata(): assert_array_almost_equal(img.darrays[0].data, img2.darrays[0].data) +def test_modify_darray(): + for fname in (DATA_FILE1, DATA_FILE2, DATA_FILE5): + img = load(fname) + darray = img.darrays[0] + darray.data[:] = 0 + assert_true(np.array_equiv(darray.data, 0)) + def test_write_newmetadata(): img = gi.GiftiImage()