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