Skip to content

Commit

Permalink
Fix EOT writing. Fallback to EOT if BOT fails (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikogabrielsson authored Nov 30, 2023
1 parent 46c19c8 commit 63168e2
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 47 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Fallback to EOT when overflowing BOT.

### Fixed

- Missing empty BOT when writing EOT.
- Fixed accessing settings for PillowEncoder.

## [0.14.0] - 2023-11-29
Expand Down
9 changes: 7 additions & 2 deletions tests/test_wsidicom_file_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from pydicom.uid import generate_uid
from tests.conftest import WsiTestDefinitions
from wsidicom import WsiDicom
from wsidicom.file.wsidicom_file_base import OffsetTableType
from wsidicom.file.wsidicom_file_target import WsiDicomFileTarget
from wsidicom.series.levels import Levels

Expand All @@ -34,7 +35,9 @@ def test_save_levels(
expected_levels_count = len(wsi.levels)

# Act
with WsiDicomFileTarget(tmp_path, generate_uid, 1, 16, "bot") as target:
with WsiDicomFileTarget(
tmp_path, generate_uid, 1, 16, OffsetTableType.BASIC, False
) as target:
target.save_levels(wsi.levels)

# Assert
Expand All @@ -57,7 +60,9 @@ def test_save_levels_add_missing(
levels_missing_smallest_levels = Levels(levels_larger_than_tile_size)

# Act
with WsiDicomFileTarget(tmp_path, generate_uid, 1, 16, "bot", True) as target:
with WsiDicomFileTarget(
tmp_path, generate_uid, 1, 16, OffsetTableType.BASIC, True
) as target:
target.save_levels(levels_missing_smallest_levels)

# Assert
Expand Down
5 changes: 3 additions & 2 deletions tests/test_wsidicom_file_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ def test_write_pixel_end(

# Act
with WsiDicomFileWriter.open(filepath, JPEGBaseline8Bit) as write_file:
write_file._write_pixel_data_end()
write_file._write_pixel_data_end_tag()

# Assert
with WsiDicomTestFile(
Expand Down Expand Up @@ -659,7 +659,8 @@ def test_create_child(
generate_uid,
1,
100,
"bot",
OffsetTableType.BASIC,
False,
) as target:
target._save_and_open_level(source_level, wsi.pixel_spacing, 2)

Expand Down
4 changes: 4 additions & 0 deletions wsidicom/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,7 @@ class WsiDicomNoResolutionError(Exception):

class WsiDicomNotSupportedError(Exception):
"""Raised if opened instance is not supported."""


class WsiDicomBotOverflow(Exception):
"""Raised if image data is to large to fit into basic table offset."""
5 changes: 4 additions & 1 deletion wsidicom/file/wsidicom_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,10 @@ def _parse_pixel_data(self) -> Tuple[List[Tuple[int, int]], OffsetTableType]:
)
if table_type == OffsetTableType.BASIC:
table = self._read_bot()
elif table_type == OffsetTableType.EMPTY:
elif (
table_type == OffsetTableType.EMPTY
or table_type == OffsetTableType.EXTENDED
):
self._read_bot_length()

if table_type == OffsetTableType.NONE:
Expand Down
7 changes: 4 additions & 3 deletions wsidicom/file/wsidicom_file_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ class OffsetTableType(Enum):
EXTENDED = "EOT"

@classmethod
def from_string(cls, offset_table: Optional[str]) -> "OffsetTableType":
def from_string(cls, offset_table: str) -> "OffsetTableType":
"""Return OffsetTableType parsed from string."""
if offset_table is None:
if offset_table == "none":
return OffsetTableType.NONE
if offset_table.strip().lower() == "empty":
return OffsetTableType.EMPTY
Expand Down Expand Up @@ -60,7 +60,8 @@ def __init__(
owned: bool = False
If the stream should be closed by this instance.
"""
self._file = DicomFileLike(stream)
self._stream = stream
self._file = DicomFileLike(self._stream)
self._filepath = filepath
self._owned = owned
self.__enter__()
Expand Down
15 changes: 7 additions & 8 deletions wsidicom/file/wsidicom_file_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ def __init__(
uid_generator: Callable[..., UID],
workers: int,
chunk_size: int,
offset_table: Optional[str],
add_missing_levels: bool = False,
offset_table: OffsetTableType,
add_missing_levels: bool,
):
"""
Create a WsiDicomFileTarget.
Expand All @@ -57,14 +57,13 @@ def __init__(
chunk_size: int
Chunk size (number of tiles) to process at a time. Actual chunk
size also depends on minimun_chunk_size from image_data.
offset_table: Optional[str]
Offset table to use, 'bot' basic offset table, 'eot' extended
offset table, None - no offset table.
add_missing_levels: bool = False
offset_table: OffsetTableType
Offset table to use.
add_missing_levels: bool
If to add missing dyadic levels up to the single tile level.
"""
self._output_path = output_path
self._offset_table = OffsetTableType.from_string(offset_table)
self._offset_table = offset_table
self._filepaths: List[Path] = []
self._opened_files: List[WsiDicomFile] = []
super().__init__(uid_generator, workers, chunk_size, add_missing_levels)
Expand Down Expand Up @@ -135,7 +134,7 @@ def _save_group(self, group: Group, scale: int = 1) -> List[Path]:
filepaths: List[Path] = []
for instances in self._group_instances_to_file(group):
uid = self._uid_generator()
filepath = Path(self._output_path).joinpath(uid + ".dcm")
filepath = self._output_path.joinpath(uid + ".dcm")
transfer_syntax = instances[0].image_data.transfer_syntax
image_data_list = self._list_image_data(instances)
focal_planes, optical_paths, tiled_size = self._get_frame_information(
Expand Down
Loading

0 comments on commit 63168e2

Please sign in to comment.