Skip to content

Commit fcb91a1

Browse files
committed
Merge branch 'main' of https://github.com/BodenmillerGroup/readimc into main
2 parents 24a4ccb + 5eb3712 commit fcb91a1

File tree

3 files changed

+37
-16
lines changed

3 files changed

+37
-16
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.8.0] - 2024-09-06
9+
10+
Added the option to return raw data for read_slide, read_panorama, read_before_ablation_image, read_after_ablation_image functions.
11+
12+
Fixed a bug where the reading of ablation image functions was returning an extra byte at the end of the DotNet Binary Serialization Record.
13+
814
## [0.7.0] - 2023-08-11
915

1016
Implemented checks for overlapping raw data blocks in MCD file metadata [#6](https://github.com/BodenmillerGroup/readimc/issues/6)

readimc/mcd_file.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,9 @@ def read_acquisition(
174174
img[:, ys, xs] = np.transpose(data[:, 3:])
175175
return img
176176

177-
def read_slide(self, slide: Slide) -> Optional[np.ndarray]:
177+
def read_slide(
178+
self, slide: Slide, raw: bool = False
179+
) -> Union[np.ndarray, bytes, None]:
178180
"""Reads and decodes a slide image as numpy array using the ``imageio``
179181
package.
180182
@@ -199,22 +201,25 @@ def read_slide(self, slide: Slide) -> Optional[np.ndarray]:
199201
if data_start_offset == data_end_offset == 0:
200202
return None
201203
data_start_offset += 161
204+
data_end_offset -= 1
202205
if data_start_offset >= data_end_offset:
203206
raise IOError(
204207
f"MCD file '{self.path.name}' corrupted: "
205208
f"invalid image data offsets for slide {slide.id}"
206209
)
207210
try:
208211
return self._read_image(
209-
data_start_offset, data_end_offset - data_start_offset
212+
data_start_offset, data_end_offset - data_start_offset, raw
210213
)
211214
except Exception as e:
212215
raise IOError(
213216
f"MCD file '{self.path.name}' corrupted: "
214217
f"cannot read image for slide {slide.id}"
215218
) from e
216219

217-
def read_panorama(self, panorama: Panorama) -> np.ndarray:
220+
def read_panorama(
221+
self, panorama: Panorama, raw: bool = False
222+
) -> Union[np.ndarray, bytes, None]:
218223
"""Reads and decodes a panorama image as numpy array using the
219224
``imageio`` package.
220225
@@ -229,15 +234,18 @@ def read_panorama(self, panorama: Panorama) -> np.ndarray:
229234
f"MCD file '{self.path.name}' corrupted: "
230235
f"cannot locate image data for panorama {panorama.id}"
231236
) from e
237+
if data_start_offset == data_end_offset == 0:
238+
return None
232239
data_start_offset += 161
240+
data_end_offset -= 1
233241
if data_start_offset >= data_end_offset:
234242
raise IOError(
235243
f"MCD file '{self.path.name}' corrupted: "
236244
f"invalid image data offsets for panorama {panorama.id}"
237245
)
238246
try:
239247
return self._read_image(
240-
data_start_offset, data_end_offset - data_start_offset
248+
data_start_offset, data_end_offset - data_start_offset, raw
241249
)
242250
except Exception as e:
243251
raise IOError(
@@ -246,8 +254,8 @@ def read_panorama(self, panorama: Panorama) -> np.ndarray:
246254
) from e
247255

248256
def read_before_ablation_image(
249-
self, acquisition: Acquisition
250-
) -> Optional[np.ndarray]:
257+
self, acquisition: Acquisition, raw: bool = False
258+
) -> Union[np.ndarray, bytes, None]:
251259
"""Reads and decodes a before-ablation image as numpy array using the
252260
``imageio`` package.
253261
@@ -270,6 +278,7 @@ def read_before_ablation_image(
270278
if data_start_offset == data_end_offset == 0:
271279
return None
272280
data_start_offset += 161
281+
data_end_offset -= 1
273282
if data_start_offset >= data_end_offset:
274283
raise IOError(
275284
f"MCD file '{self.path.name}' corrupted: "
@@ -278,7 +287,7 @@ def read_before_ablation_image(
278287
)
279288
try:
280289
return self._read_image(
281-
data_start_offset, data_end_offset - data_start_offset
290+
data_start_offset, data_end_offset - data_start_offset, raw
282291
)
283292
except Exception as e:
284293
raise IOError(
@@ -288,8 +297,8 @@ def read_before_ablation_image(
288297
) from e
289298

290299
def read_after_ablation_image(
291-
self, acquisition: Acquisition
292-
) -> Optional[np.ndarray]:
300+
self, acquisition: Acquisition, raw: bool = False
301+
) -> Union[np.ndarray, bytes, None]:
293302
"""Reads and decodes a after-ablation image as numpy array using the
294303
``imageio`` package.
295304
@@ -312,6 +321,7 @@ def read_after_ablation_image(
312321
if data_start_offset == data_end_offset == 0:
313322
return None
314323
data_start_offset += 161
324+
data_end_offset -= 1
315325
if data_start_offset >= data_end_offset:
316326
raise IOError(
317327
f"MCD file '{self.path.name}' corrupted: "
@@ -320,7 +330,7 @@ def read_after_ablation_image(
320330
)
321331
try:
322332
return self._read_image(
323-
data_start_offset, data_end_offset - data_start_offset
333+
data_start_offset, data_end_offset - data_start_offset, raw
324334
)
325335
except Exception as e:
326336
raise IOError(
@@ -358,12 +368,17 @@ def _read_schema_xml(
358368
data = mm.read(end_index + len(end_sub_encoded) - start_index)
359369
return data.decode(encoding=encoding)
360370

361-
def _read_image(self, data_offset: int, data_size: int) -> np.ndarray:
371+
def _read_image(
372+
self, data_offset: int, data_size: int, raw: bool = False
373+
) -> Union[np.ndarray, bytes]:
362374
if self._fh is None:
363375
raise IOError(f"MCD file '{self.path.name}' has not been opened")
364376
self._fh.seek(data_offset)
365377
data = self._fh.read(data_size)
366-
return imread(data)
378+
if raw:
379+
return data
380+
else:
381+
return imread(data)
367382

368383
def __repr__(self) -> str:
369384
return str(self._path)

readimc/mcd_parser.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ def _parse_slide(self, slide_elem: ET.Element) -> Slide:
123123
if panorama is not None:
124124
panorama.acquisitions.append(acquisition)
125125
for a, b in itertools.combinations(slide.acquisitions, 2):
126-
a_start = a.metadata["DataStartOffset"]
127-
a_end = a.metadata["DataEndOffset"]
128-
b_start = b.metadata["DataStartOffset"]
129-
b_end = b.metadata["DataEndOffset"]
126+
a_start = int(a.metadata["DataStartOffset"])
127+
a_end = int(a.metadata["DataEndOffset"])
128+
b_start = int(b.metadata["DataStartOffset"])
129+
b_end = int(b.metadata["DataEndOffset"])
130130
if b_start <= a_start < b_end or b_start < a_end <= b_end:
131131
warn(
132132
f"Slide {slide.id} corrupted: "

0 commit comments

Comments
 (0)