dicom_encoding/transfer_syntax/mod.rs
1//! Module containing the DICOM Transfer Syntax data structure and related methods.
2//! Similar to the DcmCodec in DCMTK, the `TransferSyntax` contains all of the necessary
3//! algorithms for decoding and encoding DICOM data in a certain transfer syntax.
4//!
5//! This crate does not host specific transfer syntaxes. Instead, they are created in
6//! other crates and registered in the global transfer syntax registry,
7//! which implements [`TransferSyntaxIndex`].
8//! For more information, please see the [`dicom-transfer-syntax-registry`] crate,
9//! which provides built-in implementations.
10//!
11//! This module allows you to register your own transfer syntaxes.
12//! With the `inventory-registry` Cargo feature,
13//! you can use the macro [`submit_transfer_syntax`](crate::submit_transfer_syntax)
14//! or [`submit_ele_transfer_syntax`](crate::submit_ele_transfer_syntax)
15//! to instruct the compiler to include your implementation in the registry.
16//! Without the `inventory`-based registry
17//! (in case your environment does not support it),
18//! you can still roll your own [transfer syntax index][1].
19//!
20//! [1]: TransferSyntaxIndex
21//! [`dicom-transfer-syntax-registry`]: https://docs.rs/dicom-transfer-syntax-registry
22
23use crate::adapters::{
24 DynPixelDataReader, DynPixelDataWriter, NeverPixelAdapter, PixelDataReader, PixelDataWriter,
25};
26use crate::decode::{
27 DecodeFrom, basic::BasicDecoder, explicit_be::ExplicitVRBigEndianDecoder,
28 explicit_le::ExplicitVRLittleEndianDecoder, implicit_le::ImplicitVRLittleEndianDecoder,
29};
30use crate::encode::{
31 EncodeTo, EncoderFor, explicit_be::ExplicitVRBigEndianEncoder,
32 explicit_le::ExplicitVRLittleEndianEncoder, implicit_le::ImplicitVRLittleEndianEncoder,
33};
34use std::io::{Read, Write};
35
36pub use byteordered::Endianness;
37
38/// A decoder with its type erased.
39pub type DynDecoder<S> = Box<dyn DecodeFrom<S>>;
40
41/// An encoder with its type erased.
42pub type DynEncoder<'w, W> = Box<dyn EncodeTo<W> + 'w>;
43
44/// A DICOM transfer syntax specifier.
45///
46/// Custom encoding and decoding capabilities
47/// are defined via the parameter types `D` and `P`,
48/// The type parameter `D` specifies
49/// an adapter for reading and writing data sets,
50/// whereas `P` specifies the encoder and decoder of encapsulated pixel data.
51///
52/// This type is usually consumed in its "type erased" form,
53/// with its default parameter types.
54/// On the other hand, implementers of `TransferSyntax` will typically specify
55/// concrete types for `D` and `P`,
56/// which are type-erased before registration.
57/// If the transfer syntax requires no data set codec,
58/// `D` can be assigned to the utility type [`NeverAdapter`].
59/// If pixel data encoding/decoding is not needed or not supported,
60/// you can assign `P` to [`NeverPixelAdapter`].
61#[derive(Debug)]
62pub struct TransferSyntax<D = DynDataRWAdapter, R = DynPixelDataReader, W = DynPixelDataWriter> {
63 /// The unique identifier of the transfer syntax.
64 uid: &'static str,
65 /// The name of the transfer syntax.
66 name: &'static str,
67 /// The byte order of data.
68 byte_order: Endianness,
69 /// Whether the transfer syntax mandates an explicit value representation,
70 /// or the VR is implicit.
71 explicit_vr: bool,
72 /// The transfer syntax' requirements and implemented capabilities.
73 codec: Codec<D, R, W>,
74}
75
76/// Wrapper type for a provider of transfer syntax descriptors.
77///
78/// This is a piece of the plugin interface for
79/// registering and collecting transfer syntaxes.
80/// Implementers and consumers of transfer syntaxes
81/// will usually not interact with it directly.
82/// In order to register a new transfer syntax,
83/// see the macro [`submit_transfer_syntax`](crate::submit_transfer_syntax).
84#[derive(Debug, Copy, Clone)]
85pub struct TransferSyntaxFactory(pub fn() -> TransferSyntax);
86
87#[cfg(feature = "inventory-registry")]
88// Collect transfer syntax specifiers from other crates.
89inventory::collect!(TransferSyntaxFactory);
90
91/// Trait for a container/repository of transfer syntax specifiers.
92///
93/// Types implementing this trait are held responsible for populating
94/// themselves with a set of transfer syntaxes, which can be fully supported,
95/// partially supported, or not supported. Usually, only one implementation
96/// of this trait is used for the entire program,
97/// the most common one being the `TransferSyntaxRegistry` type
98/// from [`transfer-syntax-registry`].
99///
100/// [`transfer-syntax-registry`]: https://docs.rs/dicom-transfer-syntax-registry
101pub trait TransferSyntaxIndex {
102 /// Obtain a DICOM transfer syntax by its respective UID.
103 ///
104 /// Implementations of this method should be robust to the possible
105 /// presence of trailing null characters (`\0`) in `uid`.
106 fn get(&self, uid: &str) -> Option<&TransferSyntax>;
107}
108
109impl<T: ?Sized> TransferSyntaxIndex for &T
110where
111 T: TransferSyntaxIndex,
112{
113 fn get(&self, uid: &str) -> Option<&TransferSyntax> {
114 (**self).get(uid)
115 }
116}
117
118#[cfg(feature = "inventory-registry")]
119#[macro_export]
120/// Submit a transfer syntax specifier to be supported by the
121/// program's runtime. This is to be used by crates wishing to provide
122/// additional support for a certain transfer syntax using the
123/// main transfer syntax registry.
124///
125/// This macro does not actually "run" anything, so place it outside of a
126/// function body at the root of the crate.
127/// The expression is evaluated when the transfer syntax registry is populated
128/// upon the first request,
129/// and must resolve to a value of type [`TransferSyntax<D, P>`],
130/// for valid definitions of the parameter types `D` and `P`.
131/// The macro will type-erase these parameters automatically.
132///
133/// # Example
134///
135/// One common use case is wanting to read data sets
136/// of DICOM objects in a private transfer syntax,
137/// even when a decoder for that pixel data is not available.
138/// By writing a simple stub at your project's root,
139/// the rest of the ecosystem will know
140/// how to read and write data sets in that transfer syntax.
141///
142/// ```
143/// use dicom_encoding::{
144/// submit_transfer_syntax, AdapterFreeTransferSyntax, Codec, Endianness,
145/// };
146///
147/// submit_transfer_syntax!(AdapterFreeTransferSyntax::new(
148/// // Transfer Syntax UID
149/// "1.3.46.670589.33.1.4.1",
150/// // Name/alias
151/// "CT Private ELE",
152/// // Data set byte order
153/// Endianness::Little,
154/// // Explicit VR (true) or Implicit VR (false)
155/// true,
156/// Codec::EncapsulatedPixelData(None, None), // pixel data codec
157/// ));
158/// ```
159///
160/// With [`Codec::EncapsulatedPixelData(None, None)`][1],
161/// we are indicating that the transfer syntax uses encapsulated pixel data.
162/// albeit without the means to decode or encode it.
163/// See the [`adapters`](crate::adapters) module
164/// to know how to write pixel data encoders and decoders.
165///
166/// [1]: Codec::EncapsulatedPixelData
167macro_rules! submit_transfer_syntax {
168 ($ts: expr) => {
169 $crate::inventory::submit! {
170 $crate::transfer_syntax::TransferSyntaxFactory(|| ($ts).erased())
171 }
172 };
173}
174
175#[cfg(not(feature = "inventory-registry"))]
176#[macro_export]
177/// Submit a transfer syntax specifier to be supported by the
178/// program's runtime. This is to be used by crates wishing to provide
179/// additional support for a certain transfer syntax using the
180/// main transfer syntax registry.
181///
182/// This macro does actually "run" anything, so place it outside of a
183/// function body at the root of the crate.
184///
185/// Without the `inventory-registry` feature, this request is ignored.
186macro_rules! submit_transfer_syntax {
187 ($ts: expr) => {
188 // ignore request
189 };
190}
191
192#[cfg(feature = "inventory-registry")]
193#[macro_export]
194/// Submit an explicit VR little endian transfer syntax specifier
195/// to be supported by the program's runtime.
196///
197/// This macro is equivalent in behavior as [`submit_transfer_syntax`](crate::submit_transfer_syntax),
198/// but it is easier to use when
199/// writing support for compressed pixel data formats,
200/// which are usually in explicit VR little endian.
201///
202/// This macro does not actually "run" anything, so place it outside of a
203/// function body at the root of the crate.
204/// The expression is evaluated when the transfer syntax registry is populated
205/// upon the first request,
206/// and must resolve to a value of type [`Codec<D, R, W>`],
207/// for valid definitions of the parameter types `D`, `R`, and `W`.
208/// The macro will type-erase these parameters automatically.
209///
210/// # Example
211///
212/// One common use case is wanting to read data sets
213/// of DICOM objects in a private transfer syntax,
214/// even when a decoder for that pixel data is not available.
215/// By writing a simple stub at your project's root,
216/// the rest of the ecosystem will know
217/// how to read and write data sets in that transfer syntax.
218///
219/// ```
220/// use dicom_encoding::{submit_ele_transfer_syntax, Codec};
221///
222/// submit_ele_transfer_syntax!(
223/// // Transfer Syntax UID
224/// "1.3.46.670589.33.1.4.1",
225/// // Name/alias
226/// "CT Private ELE",
227/// // pixel data codec
228/// Codec::encapsulated_pixel_data_stub()
229/// );
230/// ```
231///
232/// With [`Codec::EncapsulatedPixelData`],
233/// we are indicating that the transfer syntax uses encapsulated pixel data.
234/// albeit without the means to decode or encode it.
235/// See the [`adapters`](crate::adapters) module
236/// to know how to write pixel data encoders and decoders.
237macro_rules! submit_ele_transfer_syntax {
238 ($uid: expr, $name: expr, $codec: expr) => {
239 $crate::submit_transfer_syntax! {
240 $crate::TransferSyntax::new_ele(
241 $uid,
242 $name,
243 $codec
244 )
245 }
246 };
247}
248
249#[cfg(not(feature = "inventory-registry"))]
250#[macro_export]
251/// Submit an explicit VR little endian transfer syntax specifier
252/// to be supported by the program's runtime.
253///
254/// This macro is equivalent in behavior as [`submit_transfer_syntax`],
255/// but it is easier to use when
256/// writing support for compressed pixel data formats,
257/// which are usually in explicit VR little endian.
258///
259/// This macro does actually "run" anything, so place it outside of a
260/// function body at the root of the crate.
261///
262/// Without the `inventory-registry` feature, this request is ignored.
263macro_rules! submit_ele_transfer_syntax {
264 ($uid: literal, $name: literal, $codec: expr) => {
265 // ignore request
266 };
267}
268
269/// A description and possible implementation regarding
270/// the encoding and decoding requirements of a transfer syntax.
271/// This is also used as a means to describe whether pixel data is encapsulated
272/// and whether this implementation supports decoding and/or encoding it.
273///
274/// ### Type parameters
275///
276/// - `D` should implement [`DataRWAdapter`]
277/// and defines how one should read and write DICOM data sets,
278/// such as in the case for deflated data.
279/// When no special considerations for data set reading and writing
280/// are necessary, this can be set to [`NeverAdapter`].
281/// - `R` should implement [`PixelDataReader`],
282/// and enables programs to convert encapsulated pixel data fragments
283/// into native pixel data.
284/// - `W` should implement [`PixelDataWriter`],
285/// and enables programs to convert native pixel data
286/// into encapsulated pixel data.
287///
288#[derive(Debug, Clone, PartialEq)]
289pub enum Codec<D, R, W> {
290 /// No codec is required for this transfer syntax.
291 ///
292 /// Pixel data, if any, should be in its _native_, unencapsulated format.
293 None,
294 /// Pixel data for this transfer syntax is encapsulated
295 /// and likely subjected to a specific encoding process.
296 /// The first part of the tuple struct contains the pixel data decoder,
297 /// whereas the second item is for the pixel data encoder.
298 ///
299 /// Decoding of the pixel data is not supported
300 /// if the decoder is `None`.
301 /// In this case, the program should still be able to
302 /// parse DICOM data sets
303 /// and fetch the pixel data in its encapsulated form.
304 EncapsulatedPixelData(Option<R>, Option<W>),
305 /// A custom data set codec is required for reading and writing data sets.
306 ///
307 /// If the item in the tuple struct is `None`,
308 /// then no reading and writing whatsoever is supported.
309 /// This could be used by a stub of
310 /// _Deflated Explicit VR Little Endian_, for example.
311 Dataset(Option<D>),
312}
313
314impl Codec<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter> {
315 /// Create a stub codec for encapsulated pixel data
316 pub fn encapsulated_pixel_data_stub() -> Self {
317 Codec::EncapsulatedPixelData(None, None)
318 }
319}
320
321impl<R> Codec<NeverAdapter, R, NeverPixelAdapter> {
322 /// Create a codec for encapsulated pixel data
323 /// with a pixel data decoder but not an encoder
324 pub fn encapsulated_pixel_data_reader(reader: R) -> Self {
325 Codec::EncapsulatedPixelData(Some(reader), None)
326 }
327}
328
329impl<R, W> Codec<NeverAdapter, R, W> {
330 /// Create a codec for encapsulated pixel data
331 /// with a pixel data decoder and encoder
332 pub fn encapsulated_pixel_data(reader: R, writer: W) -> Self {
333 Codec::EncapsulatedPixelData(Some(reader), Some(writer))
334 }
335}
336
337/// An alias for a transfer syntax specifier with no pixel data encapsulation
338/// nor data set deflating.
339pub type AdapterFreeTransferSyntax =
340 TransferSyntax<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter>;
341
342/// A fully dynamic adapter of byte read and write streams.
343pub trait DataRWAdapter {
344 /// Adapt a byte reader.
345 fn adapt_reader<'r>(&self, reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r>;
346
347 /// Adapt a byte writer.
348 fn adapt_writer<'w>(&self, writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w>;
349}
350
351/// Alias type for a dynamically dispatched data adapter.
352pub type DynDataRWAdapter = Box<dyn DataRWAdapter + Send + Sync>;
353
354impl<T> DataRWAdapter for &'_ T
355where
356 T: DataRWAdapter,
357{
358 /// Adapt a byte reader.
359 fn adapt_reader<'r>(&self, reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r> {
360 (**self).adapt_reader(reader)
361 }
362
363 /// Adapt a byte writer.
364 fn adapt_writer<'w>(&self, writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w> {
365 (**self).adapt_writer(writer)
366 }
367}
368
369/// An immaterial type representing a data set adapter which is never required,
370/// and as such is never instantiated.
371/// Most transfer syntaxes use this,
372/// as they do not have to adapt readers and writers
373/// for encoding and decoding data sets.
374/// The main exception is in the family of
375/// _Deflated Explicit VR Little Endian_ transfer syntaxes.
376#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
377pub enum NeverAdapter {}
378
379impl DataRWAdapter for NeverAdapter {
380 fn adapt_reader<'r>(&self, _reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r> {
381 unreachable!()
382 }
383
384 fn adapt_writer<'w>(&self, _writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w> {
385 unreachable!()
386 }
387}
388
389impl<D, R, W> TransferSyntax<D, R, W> {
390 /// Create a new transfer syntax descriptor.
391 ///
392 /// Note that only transfer syntax implementers are expected to
393 /// construct TS descriptors from scratch.
394 /// For a practical usage of transfer syntaxes,
395 /// one should look up an existing transfer syntax registry by UID.
396 ///
397 /// # Example
398 ///
399 /// To register a private transfer syntax in your program,
400 /// use [`submit_transfer_syntax`](crate::submit_transfer_syntax)
401 /// outside of a function body:
402 ///
403 /// ```no_run
404 /// # use dicom_encoding::{
405 /// # submit_transfer_syntax, Codec, Endianness,
406 /// # NeverAdapter, NeverPixelAdapter, TransferSyntax,
407 /// # };
408 /// submit_transfer_syntax! {
409 /// TransferSyntax::<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter>::new(
410 /// "1.3.46.670589.33.1.4.1",
411 /// "CT-Private-ELE",
412 /// Endianness::Little,
413 /// true,
414 /// Codec::EncapsulatedPixelData(None, None),
415 /// )
416 /// }
417 /// ```
418 pub const fn new(
419 uid: &'static str,
420 name: &'static str,
421 byte_order: Endianness,
422 explicit_vr: bool,
423 codec: Codec<D, R, W>,
424 ) -> Self {
425 TransferSyntax {
426 uid,
427 name,
428 byte_order,
429 explicit_vr,
430 codec,
431 }
432 }
433
434 /// Create a new descriptor
435 /// for a transfer syntax in explicit VR little endian.
436 ///
437 /// Note that only transfer syntax implementers are expected to
438 /// construct TS descriptors from scratch.
439 /// For a practical usage of transfer syntaxes,
440 /// one should look up an existing transfer syntax registry by UID.
441 ///
442 /// # Example
443 ///
444 /// To register a private transfer syntax in your program,
445 /// use [`submit_transfer_syntax`](crate::submit_transfer_syntax)
446 /// outside of a function body:
447 ///
448 /// ```no_run
449 /// # use dicom_encoding::{
450 /// # submit_transfer_syntax, Codec,
451 /// # NeverAdapter, NeverPixelAdapter, TransferSyntax,
452 /// # };
453 /// submit_transfer_syntax! {
454 /// TransferSyntax::<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter>::new_ele(
455 /// "1.3.46.670589.33.1.4.1",
456 /// "CT-Private-ELE",
457 /// Codec::EncapsulatedPixelData(None, None),
458 /// )
459 /// }
460 /// ```
461 ///
462 /// See [`submit_ele_transfer_syntax`](crate::submit_ele_transfer_syntax)
463 /// for an alternative.
464 pub const fn new_ele(uid: &'static str, name: &'static str, codec: Codec<D, R, W>) -> Self {
465 TransferSyntax {
466 uid,
467 name,
468 byte_order: Endianness::Little,
469 explicit_vr: true,
470 codec,
471 }
472 }
473
474 /// Obtain this transfer syntax' unique identifier.
475 pub const fn uid(&self) -> &'static str {
476 self.uid
477 }
478
479 /// Obtain the name of this transfer syntax.
480 pub const fn name(&self) -> &'static str {
481 self.name
482 }
483
484 /// Obtain this transfer syntax' expected endianness.
485 pub const fn endianness(&self) -> Endianness {
486 self.byte_order
487 }
488
489 /// Obtain this transfer syntax' codec specification.
490 pub fn codec(&self) -> &Codec<D, R, W> {
491 &self.codec
492 }
493
494 /// Check whether this transfer syntax specifier provides a complete
495 /// implementation,
496 /// meaning that it can both decode and encode in this transfer syntax.
497 pub fn is_fully_supported(&self) -> bool {
498 matches!(
499 self.codec,
500 Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(Some(_), Some(_)),
501 )
502 }
503
504 /// Check whether no codecs are required for this transfer syntax,
505 /// meaning that a complete implementation is available
506 /// and no pixel data conversion is required.
507 pub fn is_codec_free(&self) -> bool {
508 matches!(self.codec, Codec::None)
509 }
510
511 /// Check whether neither reading nor writing of data sets is supported.
512 /// If this is `true`, encoding and decoding will not be available.
513 pub fn is_unsupported(&self) -> bool {
514 matches!(self.codec, Codec::Dataset(None))
515 }
516
517 /// Check whether this transfer syntax expects pixel data to be encapsulated.
518 ///
519 /// This does not imply that the pixel data can be decoded.
520 pub fn is_encapsulated_pixel_data(&self) -> bool {
521 matches!(self.codec, Codec::EncapsulatedPixelData(..))
522 }
523
524 /// Check whether reading and writing the pixel data is unsupported.
525 /// If this is `true`, encoding and decoding of the data set may still
526 /// be possible, but the pixel data will only be available in its
527 /// encapsulated form.
528 pub fn is_unsupported_pixel_encapsulation(&self) -> bool {
529 matches!(
530 self.codec,
531 Codec::Dataset(None) | Codec::EncapsulatedPixelData(None, None)
532 )
533 }
534
535 /// Check whether this codec can fully decode
536 /// both data sets and pixel data.
537 pub fn can_decode_all(&self) -> bool {
538 matches!(
539 self.codec,
540 Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(Some(_), _)
541 )
542 }
543
544 /// Check whether this codec can decode the data set.
545 pub fn can_decode_dataset(&self) -> bool {
546 matches!(
547 self.codec,
548 Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(..)
549 )
550 }
551
552 /// Retrieve the appropriate data element decoder for this transfer syntax.
553 /// Can yield none if decoding is not supported.
554 ///
555 /// The resulting decoder does not consider pixel data encapsulation or
556 /// data set compression rules. This means that the consumer of this method
557 /// needs to adapt the reader before using the decoder.
558 pub fn decoder<'s>(&self) -> Option<DynDecoder<dyn Read + 's>> {
559 self.decoder_for()
560 }
561
562 /// Retrieve the appropriate data element decoder for this transfer syntax
563 /// and given reader type (this method is not object safe).
564 /// Can yield none if decoding is not supported.
565 ///
566 /// The resulting decoder does not consider pixel data encapsulation or
567 /// data set compression rules. This means that the consumer of this method
568 /// needs to adapt the reader before using the decoder.
569 pub fn decoder_for<S>(&self) -> Option<DynDecoder<S>>
570 where
571 Self: Sized,
572 S: ?Sized + Read,
573 {
574 match (self.byte_order, self.explicit_vr) {
575 (Endianness::Little, false) => Some(Box::<ImplicitVRLittleEndianDecoder<_>>::default()),
576 (Endianness::Little, true) => Some(Box::<ExplicitVRLittleEndianDecoder>::default()),
577 (Endianness::Big, true) => Some(Box::<ExplicitVRBigEndianDecoder>::default()),
578 _ => None,
579 }
580 }
581
582 /// Retrieve the appropriate data element encoder for this transfer syntax.
583 /// Can yield none if encoding is not supported. The resulting encoder does not
584 /// consider pixel data encapsulation or data set compression rules.
585 pub fn encoder<'w>(&self) -> Option<DynEncoder<'w, dyn Write + 'w>> {
586 self.encoder_for()
587 }
588
589 /// Retrieve the appropriate data element encoder for this transfer syntax
590 /// and the given writer type (this method is not object safe).
591 /// Can yield none if encoding is not supported. The resulting encoder does not
592 /// consider pixel data encapsulation or data set compression rules.
593 pub fn encoder_for<'w, T>(&self) -> Option<DynEncoder<'w, T>>
594 where
595 Self: Sized,
596 T: ?Sized + Write + 'w,
597 {
598 match (self.byte_order, self.explicit_vr) {
599 (Endianness::Little, false) => Some(Box::new(EncoderFor::new(
600 ImplicitVRLittleEndianEncoder::default(),
601 ))),
602 (Endianness::Little, true) => Some(Box::new(EncoderFor::new(
603 ExplicitVRLittleEndianEncoder::default(),
604 ))),
605 (Endianness::Big, true) => Some(Box::new(EncoderFor::new(
606 ExplicitVRBigEndianEncoder::default(),
607 ))),
608 _ => None,
609 }
610 }
611
612 /// Obtain a dynamic basic decoder, based on this transfer syntax' expected endianness.
613 pub fn basic_decoder(&self) -> BasicDecoder {
614 BasicDecoder::from(self.endianness())
615 }
616
617 /// Obtain a reference to the underlying pixel data reader.
618 ///
619 /// Returns `None` if pixel data is not encapsulated
620 /// or a pixel data decoder implementation is not available.
621 pub fn pixel_data_reader(&self) -> Option<&R> {
622 match &self.codec {
623 Codec::EncapsulatedPixelData(r, _) => r.as_ref(),
624 _ => None,
625 }
626 }
627
628 /// Obtain a reference to the underlying pixel data writer.
629 ///
630 /// Returns `None` if pixel data is not encapsulated
631 /// or a pixel data encoder implementation is not available.
632 pub fn pixel_data_writer(&self) -> Option<&W> {
633 match &self.codec {
634 Codec::EncapsulatedPixelData(_, w) => w.as_ref(),
635 _ => None,
636 }
637 }
638
639 /// Type-erase the pixel data or data set codec.
640 pub fn erased(self) -> TransferSyntax
641 where
642 D: Send + Sync + 'static,
643 D: DataRWAdapter,
644 R: Send + Sync + 'static,
645 R: PixelDataReader,
646 W: Send + Sync + 'static,
647 W: PixelDataWriter,
648 {
649 let codec = match self.codec {
650 Codec::Dataset(d) => Codec::Dataset(d.map(|d| Box::new(d) as _)),
651 Codec::EncapsulatedPixelData(r, w) => Codec::EncapsulatedPixelData(
652 r.map(|r| Box::new(r) as _),
653 w.map(|w| Box::new(w) as _),
654 ),
655 Codec::None => Codec::None,
656 };
657
658 TransferSyntax {
659 uid: self.uid,
660 name: self.name,
661 byte_order: self.byte_order,
662 explicit_vr: self.explicit_vr,
663 codec,
664 }
665 }
666}