From a6760b173e899a277104014f3209ab953390e3eb Mon Sep 17 00:00:00 2001 From: Ruben Verweij Date: Wed, 19 Jul 2017 15:02:14 +0200 Subject: [PATCH] Test color channels, fix a bug in color channel encoding --- nd2reader/artificial.py | 25 +++++++++++++++++++++++-- nd2reader/common.py | 2 +- nd2reader/raw_metadata.py | 5 ++++- tests/test_common.py | 2 +- tests/test_raw_metadata.py | 5 +++++ 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/nd2reader/artificial.py b/nd2reader/artificial.py index 53d2677..df83c18 100644 --- a/nd2reader/artificial.py +++ b/nd2reader/artificial.py @@ -197,6 +197,8 @@ class ArtificialND2(object): raw_data = struct.pack('I', data) elif isinstance(data, float): raw_data = struct.pack('d', data) + elif isinstance(data, str): + raw_data = self._str_to_padded_bytes(data) return raw_data @@ -205,15 +207,21 @@ class ArtificialND2(object): return self.data_types['metadata_item'] elif isinstance(data, int): return self.data_types['unsigned_int'] + elif isinstance(data, str): + return self.data_types['string'] else: return self.data_types['double'] + @staticmethod + def _str_to_padded_bytes(data): + return six.b('').join([struct.pack('cx', six.b(s)) for s in data]) + struct.pack('xx') + def _pack_dict_with_metadata(self, data): raw_data = b'' for data_key in data.keys(): # names have always one character extra and are padded in zero bytes??? - b_data_key = six.b('').join([struct.pack('cx', six.b(s)) for s in data_key]) + struct.pack('xx') + b_data_key = self._str_to_padded_bytes(data_key) # header consists of data type and length of key name, it is represented by 2 unsigned chars raw_data += struct.pack('BB', self._get_data_type(data[data_key]), len(data_key) + 1) @@ -256,7 +264,20 @@ class ArtificialND2(object): }, # ImageAttributesLV!", 7, # ImageTextInfoLV!", 7, # ImageMetadataLV!", - 7, # ImageMetadataSeqLV|0!", + { + 'SLxPictureMetadata': + { + 'sPicturePlanes': + { + 'sPlaneNew': { + # channels are numbered a0, a1, ..., aN + 'a0': { + 'sDescription': 'TRITC' + } + } + } + } + }, # ImageMetadataSeqLV|0!", 7, # ImageCalibrationLV|0!", 7, # CustomData|X!", 7, # CustomData|Y!", diff --git a/nd2reader/common.py b/nd2reader/common.py index e9842d5..070b6fc 100644 --- a/nd2reader/common.py +++ b/nd2reader/common.py @@ -165,7 +165,7 @@ def _parse_string(data): try: decoded = value.decode("utf16")[:-1].encode("utf8") except UnicodeDecodeError: - decoded = value.decode('utf8') + decoded = value.decode('utf8').encode("utf8") return decoded diff --git a/nd2reader/raw_metadata.py b/nd2reader/raw_metadata.py index bc2c784..7aba42d 100644 --- a/nd2reader/raw_metadata.py +++ b/nd2reader/raw_metadata.py @@ -136,7 +136,10 @@ class RawMetadata(object): for (label, chan), valid in zip(sorted(metadata[six.b('sPlaneNew')].items()), validity): if not valid: continue - channels.append(chan[six.b('sDescription')].decode("utf8")) + if chan[six.b('sDescription')] is not None: + channels.append(chan[six.b('sDescription')].decode("utf8")) + else: + channels.append('Unknown') return channels def _parse_fields_of_view(self): diff --git a/tests/test_common.py b/tests/test_common.py index 380af7e..8e13aaa 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -104,7 +104,7 @@ class TestCommon(unittest.TestCase): test_string = 'colloid' file = self._prepare_bin_stream("%ds" % len(test_string), six.b(test_string)) parsed = _parse_string(file) - self.assertEqual(parsed, test_string) + self.assertEqual(parsed, six.b(test_string)) test_data = [1, 2, 3, 4, 5] file = self._prepare_bin_stream("Q" + ''.join(['B'] * len(test_data)), len(test_data), *test_data) diff --git a/tests/test_raw_metadata.py b/tests/test_raw_metadata.py index 3ca0463..2ff8f8d 100644 --- a/tests/test_raw_metadata.py +++ b/tests/test_raw_metadata.py @@ -57,3 +57,8 @@ class TestRawMetadata(unittest.TestCase): parsed_dict = self.metadata.image_attributes self._assert_dicts_equal(parsed_dict, self.file_data['image_attributes']) + + def test_color_channels(self): + parsed_channels = self.metadata.get_parsed_metadata()['channels'] + + self.assertEquals(parsed_channels, ['TRITC'])