dicube 0.2.0__cp312-cp312-macosx_10_9_x86_64.whl → 0.2.3__cp312-cp312-macosx_10_9_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dicube/__init__.py CHANGED
@@ -64,7 +64,7 @@ def set_num_threads(num_threads: int) -> None:
64
64
  _num_threads = num_threads
65
65
 
66
66
  # Top-level convenience methods
67
- def load(file_path: str) -> DicomCubeImage:
67
+ def load(file_path: str, skip_meta: bool = False) -> DicomCubeImage:
68
68
  """Load a DicomCubeImage from a file.
69
69
 
70
70
  Args:
@@ -73,8 +73,15 @@ def load(file_path: str) -> DicomCubeImage:
73
73
  Returns:
74
74
  DicomCubeImage: The loaded image object.
75
75
  """
76
- return DicomCubeImageIO.load(file_path)
76
+ return DicomCubeImageIO.load(file_path, skip_meta)
77
77
 
78
+ def load_meta(file_path: str) -> DicomMeta:
79
+ """Load the metadata from a file.
80
+
81
+ Args:
82
+ file_path (str): Path to the input file.
83
+ """
84
+ return DicomCubeImageIO.load_meta(file_path)
78
85
 
79
86
  def save(
80
87
  image: DicomCubeImage,
dicube/core/io.py CHANGED
@@ -107,18 +107,13 @@ class DicomCubeImageIO:
107
107
  details={"file_path": file_path, "file_type": file_type}
108
108
  ) from e
109
109
 
110
+
110
111
  @staticmethod
111
- def load(file_path: str) -> 'DicomCubeImage':
112
- """Load DicomCubeImage from a file.
112
+ def _get_reader(file_path: str) -> DcbFile:
113
+ """Get the appropriate reader based on the file path.
113
114
 
114
115
  Args:
115
- file_path (str): Input file path.
116
-
117
- Returns:
118
- DicomCubeImage: The loaded object from the file.
119
-
120
- Raises:
121
- ValueError: When the file format is not supported.
116
+ file_path (str): Path to the input file.
122
117
  """
123
118
  # Validate required parameters
124
119
  validate_not_none(file_path, "file_path", "load operation", InvalidCubeFileError)
@@ -143,9 +138,44 @@ class DicomCubeImageIO:
143
138
  details={"file_path": file_path, "magic_number": magic},
144
139
  suggestion="Ensure the file is a valid DicomCube file"
145
140
  )
141
+ return reader
142
+
143
+ except Exception as e:
144
+ if isinstance(e, (InvalidCubeFileError, CodecError)):
145
+ raise
146
+ raise InvalidCubeFileError(
147
+ f"Failed to load file: {str(e)}",
148
+ context="load operation",
149
+ details={"file_path": file_path}
150
+ ) from e
151
+
152
+ @staticmethod
153
+ def load_meta(file_path: str) -> DicomMeta:
154
+ """Load the metadata from a file.
155
+
156
+ Args:
157
+ file_path (str): Path to the input file.
158
+ """
159
+ reader = DicomCubeImageIO._get_reader(file_path)
160
+ return reader.read_meta()
161
+
162
+ @staticmethod
163
+ def load(file_path: str, skip_meta: bool = False) -> 'DicomCubeImage':
164
+ """Load DicomCubeImage from a file.
165
+
166
+ Args:
167
+ file_path (str): Input file path.
168
+
169
+ Returns:
170
+ DicomCubeImage: The loaded object from the file.
146
171
 
172
+ Raises:
173
+ ValueError: When the file format is not supported.
174
+ """
175
+ reader = DicomCubeImageIO._get_reader(file_path)
176
+ try:
147
177
  # Read file contents
148
- dicom_meta = reader.read_meta()
178
+ dicom_meta = None if skip_meta else reader.read_meta()
149
179
  space = reader.read_space()
150
180
  pixel_header = reader.read_pixel_header()
151
181
  dicom_status = reader.read_dicom_status()
@@ -239,6 +269,12 @@ class DicomCubeImageIO:
239
269
  intercept = meta.get_shared_value(CommonTags.RescaleIntercept)
240
270
  wind_center = meta.get_shared_value(CommonTags.WindowCenter)
241
271
  wind_width = meta.get_shared_value(CommonTags.WindowWidth)
272
+ try:
273
+ wind_center = float(wind_center)
274
+ wind_width = float(wind_width)
275
+ except:
276
+ wind_center = None
277
+ wind_width = None
242
278
 
243
279
  # Create pixel_header
244
280
  pixel_header = PixelDataHeader(
@@ -246,8 +282,8 @@ class DicomCubeImageIO:
246
282
  RescaleIntercept=float(intercept) if intercept is not None else 0.0,
247
283
  OriginalPixelDtype=str(images[0].dtype),
248
284
  PixelDtype=str(images[0].dtype),
249
- WindowCenter=float(wind_center) if wind_center is not None else None,
250
- WindowWidth=float(wind_width) if wind_width is not None else None,
285
+ WindowCenter=wind_center,
286
+ WindowWidth=wind_width,
251
287
  )
252
288
 
253
289
  # Validate PixelDataHeader initialization success
@@ -101,9 +101,9 @@ def _display(meta, show_shared=True, show_non_shared=True):
101
101
  Returns:
102
102
  pandas.DataFrame: Formatted metadata tables.
103
103
  """
104
+
104
105
  import pandas as pd
105
106
  from .dicom_tags import CommonTags
106
-
107
107
  # Prepare shared and non-shared data
108
108
  shared_data = []
109
109
  non_shared_data = {}
@@ -137,7 +137,7 @@ def _display(meta, show_shared=True, show_non_shared=True):
137
137
  # Process each tag
138
138
  for tag_key in meta.keys():
139
139
  tag = Tag(int(tag_key[:4], 16), int(tag_key[4:], 16))
140
- tag_name = datadict.dicom_dict_summary.get(tag, {}).get("name", f"({tag.group:04X},{tag.element:04X})")
140
+ tag_name = datadict.keyword_for_tag(tag)
141
141
  vr = meta.get_vr(tag)
142
142
 
143
143
  if meta.is_shared(tag):
@@ -198,7 +198,7 @@ def _display(meta, show_shared=True, show_non_shared=True):
198
198
  for tag in non_shared_tags
199
199
  }
200
200
  name_row = {
201
- f"({tag.group:04X},{tag.element:04X})": non_shared_data[tag.key]["Name"]
201
+ f"({tag.group:04X},{tag.element:04X})": non_shared_data[get_tag_key(tag)]["Name"]
202
202
  for tag in non_shared_tags
203
203
  }
204
204
 
@@ -206,7 +206,7 @@ def _display(meta, show_shared=True, show_non_shared=True):
206
206
  values_rows = []
207
207
  for idx in range(meta.slice_count):
208
208
  row = {
209
- f"({tag.group:04X},{tag.element:04X})": non_shared_data[tag.key]["Values"][idx]
209
+ f"({tag.group:04X},{tag.element:04X})": non_shared_data[get_tag_key(tag)]["Values"][idx]
210
210
  for tag in non_shared_tags
211
211
  }
212
212
  values_rows.append(row)
@@ -288,8 +288,11 @@ class DicomMeta:
288
288
  # Convert each dataset to a dict representation
289
289
  dicts = []
290
290
  for ds in datasets:
291
- dicts.append(ds.to_json_dict())
292
-
291
+ tmp = ds.to_json_dict(
292
+ bulk_data_threshold=10240, bulk_data_element_handler=lambda x: None
293
+ )
294
+ tmp.pop(get_tag_key(CommonTags.PixelData), None)
295
+ dicts.append(tmp)
293
296
  # Merge the dictionaries
294
297
  merged_data = _merge_dataset_list(dicts)
295
298
  return cls(merged_data, filenames)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: dicube
3
- Version: 0.2.0
3
+ Version: 0.2.3
4
4
  Summary: Medical Image Storage Library with DICOM compatibility
5
5
  Author: Fangzhou Liao
6
6
  License: MIT
@@ -38,6 +38,7 @@ Requires-Dist: mypy>=1.0.0; extra == "dev"
38
38
  Requires-Dist: build>=0.8.0; extra == "dev"
39
39
  Requires-Dist: pylibjpeg>=2.0; extra == "dev"
40
40
  Requires-Dist: pylibjpeg-openjpeg>=2.0; extra == "dev"
41
+ Requires-Dist: nibabel>=3.2.0; extra == "dev"
41
42
  Provides-Extra: all
42
43
  Requires-Dist: pybind11>=2.10.0; extra == "all"
43
44
  Requires-Dist: nibabel>=3.2.0; extra == "all"
@@ -1,4 +1,4 @@
1
- dicube/__init__.py,sha256=TK2-JGOB_aPa6ilHw4WUc9l5Whc3Fb-tlZSPzbf5HIw,4886
1
+ dicube/__init__.py,sha256=aXkL9me2X6Msreu30ui2wbdguLV_kqe7UH23nmSFd4E,5125
2
2
  dicube/exceptions.py,sha256=YrwBD93oWI4yhvFfO-SOPCNMQ4z_1FSVL2gCVSnx-LU,6689
3
3
  dicube/validation.py,sha256=Edmx3yKhRShdzvM7uRK6N9j58GNV8rUv_k9w43JcaMs,12478
4
4
  dicube/codecs/__init__.py,sha256=NNus-iAv4JXsNH1kALf5vnLYnESFBoYaN72yJ7kQoqk,3754
@@ -14,7 +14,7 @@ dicube/codecs/jph/ojph_complete.cpython-311-darwin.so,sha256=SmXvkyjn1iCLHfLcmav
14
14
  dicube/codecs/jph/ojph_decode_complete.cpython-311-darwin.so,sha256=1aXbLZWb6nDX4e2S73dcWW8BnMUytk5AtWIzyxt4aiM,449096
15
15
  dicube/codecs/jph/ojph_decode_complete.cpython-39-darwin.so,sha256=OMAfYyAQra6xF_Zv5Y-LGBkg68MYpTK4qwB8lWqlf6U,448968
16
16
  dicube/codecs/jph/codec.py,sha256=d4bAoVAatSrWiC1k7gQLzWODZZTGo_1xeRRXO0NAtqo,5460
17
- dicube/core/io.py,sha256=WpzcjRtalIhi0P7EFwR5i2YLoZKz3_V_IlMOKvfDXFY,15514
17
+ dicube/core/io.py,sha256=cR7OrFk7k2lXsUy-Yi9VgkApeOEv7GBtjrX1GSFW12g,16600
18
18
  dicube/core/__init__.py,sha256=tU9vaPHbTkF8V78T8D6werr0nC7k6bMPIlatEIEdHU4,656
19
19
  dicube/core/pixel_header.py,sha256=x3-gNiyL4lFRQ6c1TVdvsm2mG36xCQx78hq4vjYkqJI,4005
20
20
  dicube/core/image.py,sha256=DAyBwKlWeCU6oDWsmdSdAzVW3IieHNLUINIAhS_ZtRg,14177
@@ -23,13 +23,13 @@ dicube/storage/__init__.py,sha256=q36sJqdI9acURBXjOW_g3QiyHw0XLGFCukMsQ-qioZc,46
23
23
  dicube/storage/dcb_file.py,sha256=GfOx2C6fexKojxwzak3_Q0K3gRBHB_UTMNVBY4NPRzg,31232
24
24
  dicube/storage/pixel_utils.py,sha256=-xMMnjSMzYk6WRvLAPktMELhSXJPmLBnt5wxKgOw5zg,9759
25
25
  dicube/dicom/dcb_streaming.py,sha256=Acsdusc6jIKuu1kd-VuDOoteZGdpt3UmwsxF-HQYZtM,9088
26
- dicube/dicom/dicom_meta.py,sha256=Iv-kEcV39vhK2qgSqGpqDhgg28RuUm8ddzSdpToIVPc,26813
26
+ dicube/dicom/dicom_meta.py,sha256=Fvhid95Gu4qqRX9zMDbIDX1t--KIYyIRvfSUQnERGis,26947
27
27
  dicube/dicom/dicom_io.py,sha256=EBa72RGHfifFKygBwCWf6r2YCTNxE9onO8d65ws_5VU,4917
28
28
  dicube/dicom/dicom_status.py,sha256=NXi-sj3mhyaFGfpechewTjhI201vziVsyfLotsLr3Fs,10117
29
29
  dicube/dicom/__init__.py,sha256=9b7liSXx5vlpEYAr59GZGkcUw16kULELTX5SlLfcXPw,371
30
30
  dicube/dicom/merge_utils.py,sha256=6flzoK_6gzpvv4WSTaWq4SjVdr1gh3gtUPMsRfKDSNM,9312
31
31
  dicube/dicom/space_from_meta.py,sha256=__B7UTmvgV1N-LMJg9O_ObHgNWa39mbRF4ZSkQXm3Vs,2420
32
32
  dicube/dicom/dicom_tags.py,sha256=sOjrK9SoAhGqynF0e3YH70j8wbtvwGRezV-tM0wp40Q,3945
33
- dicube-0.2.0.dist-info/RECORD,,
34
- dicube-0.2.0.dist-info/WHEEL,sha256=wU0uEto50UFyZnJeUzxIxZzOotEliaXdZ5JHA-mW1ew,115
35
- dicube-0.2.0.dist-info/METADATA,sha256=xDYbYiX9NKyLH0bAbBNOsziAxvXHyyQyELP8RlGA5ys,10581
33
+ dicube-0.2.3.dist-info/RECORD,,
34
+ dicube-0.2.3.dist-info/WHEEL,sha256=wU0uEto50UFyZnJeUzxIxZzOotEliaXdZ5JHA-mW1ew,115
35
+ dicube-0.2.3.dist-info/METADATA,sha256=NWFpkVhrchy-PksUdnOaC3WnpGb35w7XebMFavyqYF8,10627
File without changes