Skip to content

Commit 5a97dd4

Browse files
authored
Change plugin handling to be more agnostic (#39)
1 parent 56b9fec commit 5a97dd4

File tree

10 files changed

+64
-480
lines changed

10 files changed

+64
-480
lines changed

docs/release_notes/v1.1.0.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@
22

33
1.1.0
44
=====
5+
6+
* Simplified the plugin interface
7+
* Removed the ``plugins`` and ``_config`` modules
8+
* Added ``utils.get_decoders()`` function
9+
* Added ``pydicom.utils.get_pixel_data_decoders()`` function

pylibjpeg/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55

66

77
from ._version import __version__
8-
from ._config import PLUGINS
9-
from .plugins import load_plugins
10-
from .utils import decode
8+
from .utils import decode, add_handler
119

1210

1311
# Setup default logging
@@ -27,11 +25,11 @@ def debug_logger():
2725
logger.addHandler(handler)
2826

2927

30-
load_plugins(PLUGINS)
28+
#load_plugins()
3129

3230

3331
# Must be after loading the plugins
34-
from .utils import add_handler
32+
3533

3634
try:
3735
import pydicom

pylibjpeg/_config.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

pylibjpeg/plugins.py

Lines changed: 0 additions & 60 deletions
This file was deleted.

pylibjpeg/pydicom/pixel_data_handler.py

Lines changed: 10 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -39,63 +39,28 @@
3939
import logging
4040

4141
import numpy as np
42+
4243
from pydicom.encaps import generate_pixel_data_frame
4344
from pydicom.pixel_data_handlers.util import pixel_dtype, get_expected_length
4445

45-
from pylibjpeg.pydicom.utils import get_uid_decoder_dict
46+
from .utils import get_pixel_data_decoders
4647

4748

4849
LOGGER = logging.getLogger(__name__)
4950

5051

51-
try:
52-
import pylibjpeg.plugins.libjpeg
53-
HAVE_LIBJPEG = True
54-
LOGGER.debug("libjpeg available to the pixel data handler")
55-
except ImportError:
56-
HAVE_LIBJPEG = False
57-
LOGGER.debug("libjpeg unavailable to the pixel data handler")
58-
59-
try:
60-
import pylibjpeg.plugins.openjpeg
61-
HAVE_OPENJPEG = True
62-
LOGGER.debug("openjpeg available to the pixel data handler")
63-
except ImportError:
64-
HAVE_OPENJPEG = False
65-
LOGGER.debug("openjpeg unavailable to the pixel data handler")
66-
67-
6852
HANDLER_NAME = 'pylibjpeg'
6953
DEPENDENCIES = {
7054
'numpy': ('http://www.numpy.org/', 'NumPy'),
71-
'libjpeg': (
72-
'http://github.com/pydicom/pylibjpeg-libjpeg/', 'libjpeg plugin'
73-
),
74-
'openjpeg': (
75-
'http://github.com/pydicom/pylibjpeg-openjpeg/', 'openjpeg plugin'
76-
),
7755
}
7856

79-
80-
_DECODERS = get_uid_decoder_dict()
81-
_LIBJPEG_SYNTAXES = [
82-
'1.2.840.10008.1.2.4.50',
83-
'1.2.840.10008.1.2.4.51',
84-
'1.2.840.10008.1.2.4.57',
85-
'1.2.840.10008.1.2.4.70',
86-
'1.2.840.10008.1.2.4.80',
87-
'1.2.840.10008.1.2.4.81'
88-
]
89-
_OPENJPEG_SYNTAXES = [
90-
'1.2.840.10008.1.2.4.90',
91-
'1.2.840.10008.1.2.4.91'
92-
]
93-
SUPPORTED_TRANSFER_SYNTAXES = _LIBJPEG_SYNTAXES + _OPENJPEG_SYNTAXES
57+
_DECODERS = get_pixel_data_decoders()
58+
SUPPORTED_TRANSFER_SYNTAXES = list(_DECODERS.keys())
9459

9560

9661
def is_available():
9762
"""Return ``True`` if the handler has its dependencies met."""
98-
return HAVE_LIBJPEG or HAVE_OPENJPEG
63+
return True
9964

10065

10166
def supports_transfer_syntax(tsyntax):
@@ -134,13 +99,8 @@ def get_pixeldata(ds):
13499
Parameters
135100
----------
136101
ds : pydicom.dataset.Dataset
137-
The :class:`Dataset` containing an Image Pixel, Floating Point Image
138-
Pixel or Double Floating Point Image Pixel module and the
139-
*Pixel Data*, *Float Pixel Data* or *Double Float Pixel Data* to be
140-
converted. If (0028,0004) *Photometric Interpretation* is
141-
`'YBR_FULL_422'` then the pixel data will be
142-
resampled to 3 channel data as per Part 3, :dcm:`Annex C.7.6.3.1.2
143-
<part03/sect_C.7.6.3.html#sect_C.7.6.3.1.2>` of the DICOM Standard.
102+
The :class:`Dataset` containing an Image Pixel module and the
103+
*Pixel Data* to be converted.
144104
145105
Returns
146106
-------
@@ -161,20 +121,9 @@ def get_pixeldata(ds):
161121
# The check of transfer syntax must be first
162122
if tsyntax not in SUPPORTED_TRANSFER_SYNTAXES:
163123
raise NotImplementedError(
164-
"Unable to convert the pixel data as the transfer syntax "
165-
"is not supported by the pylibjpeg pixel data handler."
166-
)
167-
168-
if tsyntax in _LIBJPEG_SYNTAXES and not HAVE_LIBJPEG:
169-
raise RuntimeError(
170-
"The libjpeg plugin is required to decode pixel data with a "
171-
"transfer syntax of '{}'".format(tsyntax)
172-
)
173-
174-
if tsyntax in _OPENJPEG_SYNTAXES and not HAVE_OPENJPEG:
175-
raise RuntimeError(
176-
"The openjpeg plugin is required to decode pixel data with a "
177-
"transfer syntax of '{}'".format(tsyntax)
124+
"Unable to convert the pixel data as there are no pylibjpeg "
125+
"plugins available to decode pixel data encoded using '{}'"
126+
.format(tsyntax.name)
178127
)
179128

180129
# Check required elements

pylibjpeg/pydicom/utils.py

Lines changed: 7 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,6 @@
11
"""Utilities for pydicom and DICOM pixel data"""
22

3-
from pylibjpeg.plugins import *
4-
5-
6-
def decoder_from_uid(uid):
7-
"""Return a JPEG decoder for `uid`.
8-
9-
Parameters
10-
----------
11-
uid : str or pydicom.uid.UID
12-
The *Transfer Syntax UID* that the pixel data has been encoded with.
13-
14-
Returns
15-
-------
16-
callable
17-
A callable function that can be used to decode the JPEG format
18-
corresponding to `uid`.
19-
"""
20-
decoders = get_dicom_decoders()
21-
for name in decoders:
22-
try:
23-
return decoders[name][uid]
24-
except KeyError:
25-
pass
26-
27-
msg = (
28-
"No decoder is available for the Transfer Syntax UID - '{}'"
29-
.format(uid)
30-
)
31-
raise NotImplementedError(msg)
32-
33-
34-
def encoder_from_uid(uid):
35-
"""Return a JPEG encoder for `uid`.
36-
37-
Parameters
38-
----------
39-
uid : str or pydicom.uid.UID
40-
The *Transfer Syntax UID* that the pixel data will be encoded with.
41-
42-
Returns
43-
-------
44-
callable
45-
A callable function that can be used to encode to the JPEG format
46-
corresponding to `uid`.
47-
"""
48-
encoders = get_dicom_encoders()
49-
for name in encoders:
50-
try:
51-
return encoders[name][uid]
52-
except KeyError:
53-
pass
54-
55-
msg = (
56-
"No encoder is available for the Transfer Syntax UID - '{}'"
57-
.format(uid)
58-
)
59-
raise NotImplementedError(msg)
3+
from pkg_resources import iter_entry_points
604

615

626
def generate_frames(ds):
@@ -75,7 +19,7 @@ def generate_frames(ds):
7519
from pydicom.encaps import generate_pixel_data_frame
7620
from pydicom.pixel_data_handlers.util import pixel_dtype
7721

78-
decoders = get_uid_decoder_dict()
22+
decoders = get_pixel_data_decoders()
7923
decode = decoders[ds.file_meta.TransferSyntaxUID]
8024

8125
p_interp = ds.PhotometricInterpretation
@@ -85,73 +29,13 @@ def generate_frames(ds):
8529
yield reshape_frame(ds, arr)
8630

8731

88-
def get_decodable_uids():
89-
"""Return a list of decodable *Transfer Syntax UIDs*."""
90-
uids = []
91-
for name, uid_coder in get_dicom_decoders().items():
92-
uids += uid_coder.keys()
93-
94-
return list(set(uids))
95-
96-
97-
def get_dicom_decoders():
98-
"""Return available plugins with DICOM decoders.
99-
100-
Returns
101-
-------
102-
dict
103-
A ``dict`` containing the available DICOM decoders as
104-
``{plugin name : {UID : callable}}``.
105-
"""
106-
decoders = {
107-
k: getattr(globals()[k], 'DICOM_DECODERS', {}) for k in get_plugins()
108-
}
109-
110-
return decoders
111-
112-
113-
def get_dicom_encoders():
114-
"""Return available plugins with DICOM encoders.
115-
116-
Returns
117-
-------
118-
dict
119-
A ``dict`` containing the available DICOM encoders as
120-
``{plugin name : {UID : callable}}``.
121-
"""
122-
encoders = {
123-
k: getattr(globals()[k], 'DICOM_ENCODERS', {}) for k in get_plugins()
32+
def get_pixel_data_decoders():
33+
"""Return a :class:`dict` of {UID: callable}."""
34+
return {
35+
val.name: val.load()
36+
for val in iter_entry_points('pylibjpeg.pixel_data_decoders')
12437
}
12538

126-
return encoders
127-
128-
129-
def get_encodable_uids():
130-
"""Return a list of encodable *Transfer Syntax UIDs*."""
131-
uids = []
132-
for name, uid_coder in get_dicom_encoders().items():
133-
uids += uid_coder.keys()
134-
135-
return list(set(uids))
136-
137-
138-
def get_uid_decoder_dict():
139-
"""Return a :class:`dict` of {UID: decoder}."""
140-
decoder_dict = {}
141-
for _, uid_decoder_dict in get_dicom_decoders().items():
142-
decoder_dict.update(uid_decoder_dict)
143-
144-
return decoder_dict
145-
146-
147-
def get_uid_encoder_dict():
148-
"""Return a :class:`dict` of {UID: encoder}."""
149-
encoder_dict = {}
150-
for _, uid_encoder_dict in get_dicom_encoders().items():
151-
encoder_dict.update(uid_encoder_dict)
152-
153-
return encoder_dict
154-
15539

15640
def reshape_frame(ds, arr):
15741
"""Return a reshaped :class:`numpy.ndarray` `arr`.

0 commit comments

Comments
 (0)