Browse Source

#66 lol

zolfa-add_slices_loading
jim 9 years ago
parent
commit
12512a5a1a
3 changed files with 62 additions and 42 deletions
  1. +0
    -0
      nd2reader/driver/__init__.py
  2. +11
    -0
      nd2reader/parser/parser.py
  3. +51
    -42
      nd2reader/parser/v3.py

+ 0
- 0
nd2reader/driver/__init__.py View File


+ 11
- 0
nd2reader/parser/parser.py View File

@ -1,5 +1,6 @@
from nd2reader.parser.v3 import V3Parser from nd2reader.parser.v3 import V3Parser
from nd2reader.exc import InvalidVersionError from nd2reader.exc import InvalidVersionError
from abc import abstractproperty
def get_parser(filename, major_version, minor_version): def get_parser(filename, major_version, minor_version):
@ -8,3 +9,13 @@ def get_parser(filename, major_version, minor_version):
if not parser: if not parser:
raise InvalidVersionError("No parser is available for that version.") raise InvalidVersionError("No parser is available for that version.")
return parser(filename) return parser(filename)
class BaseParser(object):
@abstractproperty
def metadata(self):
raise NotImplementedError
@abstractproperty
def driver(self):
raise NotImplementedError

+ 51
- 42
nd2reader/parser/v3.py View File

@ -3,12 +3,13 @@
import array import array
from datetime import datetime from datetime import datetime
from nd2reader.model.metadata import Metadata from nd2reader.model.metadata import Metadata
from nd2reader.parser.parser import BaseParser
import re import re
import six import six
import struct import struct
class V3Parser(object):
class V3Parser(BaseParser):
""" Parses ND2 files and creates a Metadata and ImageReader object. """ """ Parses ND2 files and creates a Metadata and ImageReader object. """
CHUNK_HEADER = 0xabeceda CHUNK_HEADER = 0xabeceda
CHUNK_MAP_START = six.b("ND2 FILEMAP SIGNATURE NAME 0001!") CHUNK_MAP_START = six.b("ND2 FILEMAP SIGNATURE NAME 0001!")
@ -19,6 +20,36 @@ class V3Parser(object):
self._fh = None self._fh = None
self._metadata = None self._metadata = None
@property
def metadata(self):
if not self._metadata:
self._parse_metadata()
return self.metadata
@property
def driver(self):
raise NotImplementedError
def _parse_metadata(self):
"""
Reads all metadata.
"""
metadata_dict = {}
label_map = self._build_label_map()
for label in label_map.keys():
if label.endswith(six.b("LV!")) or six.b("LV|") in label:
data = self._read_chunk(label_map[label])
stop = label.index(six.b("LV"))
metadata_dict[label[:stop]] = self._read_metadata(data, 1)
channels = self._parse_channels(metadata_dict)
date = self._parse_fields_of_view(metadata_dict)
fields_of_view = self._parse_fields_of_view(metadata_dict)
frames = self._parse_frames(metadata_dict)
z_levels = self._parse_z_levels(metadata_dict)
self._metadata = Metadata(channels, date, fields_of_view, frames, z_levels)
def _parse_date(self, metadata_dict): def _parse_date(self, metadata_dict):
""" """
The date and time when acquisition began. The date and time when acquisition began.
@ -98,8 +129,7 @@ class V3Parser(object):
""" """
return self._parse_dimension(r""".*?Z\((\d+)\).*?""", metadata_dict) return self._parse_dimension(r""".*?Z\((\d+)\).*?""", metadata_dict)
@property
def _file_handle(self):
def _get_file_handle(self):
if self._fh is None: if self._fh is None:
self._fh = open(self._filename, "rb") self._fh = open(self._filename, "rb")
return self._fh return self._fh
@ -128,18 +158,14 @@ class V3Parser(object):
return dimension_text return dimension_text
def _parse_dimension(self, pattern, metadata_dict): def _parse_dimension(self, pattern, metadata_dict):
try:
dimension_text = self._parse_dimension_text(metadata_dict)
count = int(re.match(pattern, dimension_text).group(1))
except AttributeError:
dimension_text = self._parse_dimension_text(metadata_dict)
if six.PY3:
dimension_text = dimension_text.decode("utf8")
match = re.match(pattern, dimension_text)
if not match:
return [0] return [0]
except TypeError:
match = re.match(pattern, dimension_text.decode("utf8"))
if not match:
return [0]
return list(range(int(match.group(1))))
else:
return list(range(count))
count = int(match.group(1))
return list(range(count))
def _parse_total_images_per_channel(self, metadata_dict): def _parse_total_images_per_channel(self, metadata_dict):
""" """
@ -150,26 +176,6 @@ class V3Parser(object):
""" """
return metadata_dict[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiSequenceCount')] return metadata_dict[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiSequenceCount')]
def _parse_metadata(self):
"""
Reads all metadata.
"""
metadata_dict = {}
label_map = self._build_label_map()
for label in label_map.keys():
if label.endswith(six.b("LV!")) or six.b("LV|") in label:
data = self._read_chunk(label_map[label])
stop = label.index(six.b("LV"))
metadata_dict[label[:stop]] = self._read_metadata(data, 1)
channels = self._parse_channels(metadata_dict)
date = self._parse_fields_of_view(metadata_dict)
fields_of_view = self._parse_fields_of_view(metadata_dict)
frames = self._parse_frames(metadata_dict)
z_levels = self._parse_z_levels(metadata_dict)
self._metadata = Metadata(channels, date, fields_of_view, frames, z_levels)
def _build_label_map(self): def _build_label_map(self):
""" """
Every label ends with an exclamation point, however, we can't directly search for those to find all the labels Every label ends with an exclamation point, however, we can't directly search for those to find all the labels
@ -180,10 +186,10 @@ class V3Parser(object):
""" """
label_map = {} label_map = {}
self._file_handle.seek(-8, 2)
chunk_map_start_location = struct.unpack("Q", self._file_handle.read(8))[0]
self._file_handle.seek(chunk_map_start_location)
raw_text = self._file_handle.read(-1)
self._get_file_handle().seek(-8, 2)
chunk_map_start_location = struct.unpack("Q", self._get_file_handle().read(8))[0]
self._get_file_handle().seek(chunk_map_start_location)
raw_text = self._get_file_handle().read(-1)
label_start = raw_text.index(V3Parser.CHUNK_MAP_START) + 32 label_start = raw_text.index(V3Parser.CHUNK_MAP_START) + 32
while True: while True:
@ -202,16 +208,19 @@ class V3Parser(object):
Gets the data for a given chunk pointer Gets the data for a given chunk pointer
""" """
self._file_handle.seek(chunk_location)
self._get_file_handle().seek(chunk_location)
# The chunk metadata is always 16 bytes long # The chunk metadata is always 16 bytes long
chunk_metadata = self._file_handle.read(16)
chunk_metadata = self._get_file_handle().read(16)
header, relative_offset, data_length = struct.unpack("IIQ", chunk_metadata) header, relative_offset, data_length = struct.unpack("IIQ", chunk_metadata)
if header != V3Parser.CHUNK_HEADER: if header != V3Parser.CHUNK_HEADER:
raise ValueError("The ND2 file seems to be corrupted.") raise ValueError("The ND2 file seems to be corrupted.")
# We start at the location of the chunk metadata, skip over the metadata, and then proceed to the # We start at the location of the chunk metadata, skip over the metadata, and then proceed to the
# start of the actual data field, which is at some arbitrary place after the metadata. # start of the actual data field, which is at some arbitrary place after the metadata.
self._file_handle.seek(chunk_location + 16 + relative_offset)
return self._file_handle.read(data_length)
self._get_file_handle().seek(chunk_location + 16 + relative_offset)
val = self._get_file_handle().read(data_length)
print("**************************")
print(type(val))
return val
def _parse_unsigned_char(self, data): def _parse_unsigned_char(self, data):
return struct.unpack("B", data.read(1))[0] return struct.unpack("B", data.read(1))[0]


Loading…
Cancel
Save