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, PartialEq)]
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::EncapsulatedPixelData(None, None)
230/// );
231/// ```
232///
233/// With [`Codec::EncapsulatedPixelData(None, None)`][1],
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.
238///
239/// [1]: Codec::EncapsulatedPixelData
240macro_rules! submit_ele_transfer_syntax {
241    ($uid: expr, $name: expr, $codec: expr) => {
242        $crate::submit_transfer_syntax! {
243            $crate::AdapterFreeTransferSyntax::new_ele(
244                $uid,
245                $name,
246                $codec
247            )
248        }
249    };
250}
251
252#[cfg(not(feature = "inventory-registry"))]
253#[macro_export]
254/// Submit an explicit VR little endian transfer syntax specifier
255/// to be supported by the program's runtime.
256///
257/// This macro is equivalent in behavior as [`submit_transfer_syntax`],
258/// but it is easier to use when
259/// writing support for compressed pixel data formats,
260/// which are usually in explicit VR little endian.
261///
262/// This macro does actually "run" anything, so place it outside of a
263/// function body at the root of the crate.
264///
265/// Without the `inventory-registry` feature, this request is ignored.
266macro_rules! submit_ele_transfer_syntax {
267    ($uid: literal, $name: literal, $codec: expr) => {
268        // ignore request
269    };
270}
271
272/// A description and possible implementation regarding
273/// the encoding and decoding requirements of a transfer syntax.
274/// This is also used as a means to describe whether pixel data is encapsulated
275/// and whether this implementation supports decoding and/or encoding it.
276///
277/// ### Type parameters
278///
279/// - `D` should implement [`DataRWAdapter`]
280///   and defines how one should read and write DICOM data sets,
281///   such as in the case for deflated data.
282///   When no special considerations for data set reading and writing
283///   are necessary, this can be set to [`NeverAdapter`].
284/// - `R` should implement [`PixelDataReader`],
285///   and enables programs to convert encapsulated pixel data fragments
286///   into native pixel data.
287/// - `W` should implement [`PixelDataWriter`],
288///   and enables programs to convert native pixel data
289///   into encapsulated pixel data.
290///
291#[derive(Debug, Clone, PartialEq)]
292pub enum Codec<D, R, W> {
293    /// No codec is required for this transfer syntax.
294    ///
295    /// Pixel data, if any, should be in its _native_, unencapsulated format.
296    None,
297    /// Pixel data for this transfer syntax is encapsulated
298    /// and likely subjected to a specific encoding process.
299    /// The first part of the tuple struct contains the pixel data decoder,
300    /// whereas the second item is for the pixel data encoder.
301    ///
302    /// Decoding of the pixel data is not supported
303    /// if the decoder is `None`.
304    /// In this case, the program should still be able to
305    /// parse DICOM data sets
306    /// and fetch the pixel data in its encapsulated form.
307    EncapsulatedPixelData(Option<R>, Option<W>),
308    /// A custom data set codec is required for reading and writing data sets.
309    ///
310    /// If the item in the tuple struct is `None`,
311    /// then no reading and writing whatsoever is supported.
312    /// This could be used by a stub of
313    /// _Deflated Explicit VR Little Endian_, for example.
314    Dataset(Option<D>),
315}
316
317/// An alias for a transfer syntax specifier with no pixel data encapsulation
318/// nor data set deflating.
319pub type AdapterFreeTransferSyntax =
320    TransferSyntax<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter>;
321
322/// An adapter of byte read and write streams.
323pub trait DataRWAdapter<R, W> {
324    /// The type of the adapted reader.
325    type Reader: Read;
326    /// The type of the adapted writer.
327    type Writer: Write;
328
329    /// Adapt a byte reader.
330    fn adapt_reader(&self, reader: R) -> Self::Reader
331    where
332        R: Read;
333
334    /// Adapt a byte writer.
335    fn adapt_writer(&self, writer: W) -> Self::Writer
336    where
337        W: Write;
338}
339
340/// Alias type for a dynamically dispatched data adapter.
341pub type DynDataRWAdapter = Box<
342    dyn DataRWAdapter<
343            Box<dyn Read>,
344            Box<dyn Write>,
345            Reader = Box<dyn Read>,
346            Writer = Box<dyn Write>,
347        > + Send
348        + Sync,
349>;
350
351impl<'a, T, R, W> DataRWAdapter<R, W> for &'a T
352where
353    T: DataRWAdapter<R, W>,
354    R: Read,
355    W: Write,
356{
357    type Reader = <T as DataRWAdapter<R, W>>::Reader;
358    type Writer = <T as DataRWAdapter<R, W>>::Writer;
359
360    /// Adapt a byte reader.
361    fn adapt_reader(&self, reader: R) -> Self::Reader
362    where
363        R: Read,
364    {
365        (**self).adapt_reader(reader)
366    }
367
368    /// Adapt a byte writer.
369    fn adapt_writer(&self, writer: W) -> Self::Writer
370    where
371        W: Write,
372    {
373        (**self).adapt_writer(writer)
374    }
375}
376
377/// An immaterial type representing a data set adapter which is never required,
378/// and as such is never instantiated.
379/// Most transfer syntaxes use this,
380/// as they do not have to adapt readers and writers
381/// for encoding and decoding data sets.
382/// The main exception is in the family of
383/// _Deflated Explicit VR Little Endian_ transfer syntaxes.
384#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
385pub enum NeverAdapter {}
386
387impl<R, W> DataRWAdapter<R, W> for NeverAdapter {
388    type Reader = Box<dyn Read>;
389    type Writer = Box<dyn Write>;
390
391    fn adapt_reader(&self, _reader: R) -> Self::Reader
392    where
393        R: Read,
394    {
395        unreachable!()
396    }
397
398    fn adapt_writer(&self, _writer: W) -> Self::Writer
399    where
400        W: Write,
401    {
402        unreachable!()
403    }
404}
405
406impl<D, R, W> TransferSyntax<D, R, W> {
407    /// Create a new transfer syntax descriptor.
408    ///
409    /// Note that only transfer syntax implementers are expected to
410    /// construct TS descriptors from scratch.
411    /// For a practical usage of transfer syntaxes,
412    /// one should look up an existing transfer syntax registry by UID.
413    ///
414    /// # Example
415    ///
416    /// To register a private transfer syntax in your program,
417    /// use [`submit_transfer_syntax`](crate::submit_transfer_syntax)
418    /// outside of a function body:
419    ///  
420    /// ```no_run
421    /// # use dicom_encoding::{
422    /// #     submit_transfer_syntax, Codec, Endianness,
423    /// #     NeverAdapter, NeverPixelAdapter, TransferSyntax,
424    /// # };
425    /// submit_transfer_syntax! {
426    ///     TransferSyntax::<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter>::new(
427    ///         "1.3.46.670589.33.1.4.1",
428    ///         "CT-Private-ELE",
429    ///         Endianness::Little,
430    ///         true,
431    ///         Codec::EncapsulatedPixelData(None, None),
432    ///     )
433    /// }
434    /// ```
435    pub const fn new(
436        uid: &'static str,
437        name: &'static str,
438        byte_order: Endianness,
439        explicit_vr: bool,
440        codec: Codec<D, R, W>,
441    ) -> Self {
442        TransferSyntax {
443            uid,
444            name,
445            byte_order,
446            explicit_vr,
447            codec,
448        }
449    }
450
451    /// Create a new descriptor
452    /// for a transfer syntax in explicit VR little endian.
453    ///
454    /// Note that only transfer syntax implementers are expected to
455    /// construct TS descriptors from scratch.
456    /// For a practical usage of transfer syntaxes,
457    /// one should look up an existing transfer syntax registry by UID.
458    ///
459    /// # Example
460    ///
461    /// To register a private transfer syntax in your program,
462    /// use [`submit_transfer_syntax`](crate::submit_transfer_syntax)
463    /// outside of a function body:
464    ///  
465    /// ```no_run
466    /// # use dicom_encoding::{
467    /// #     submit_transfer_syntax, Codec,
468    /// #     NeverAdapter, NeverPixelAdapter, TransferSyntax,
469    /// # };
470    /// submit_transfer_syntax! {
471    ///     TransferSyntax::<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter>::new_ele(
472    ///         "1.3.46.670589.33.1.4.1",
473    ///         "CT-Private-ELE",
474    ///         Codec::EncapsulatedPixelData(None, None),
475    ///     )
476    /// }
477    /// ```
478    ///
479    /// See [`submit_ele_transfer_syntax`](crate::submit_ele_transfer_syntax)
480    /// for an alternative.
481    pub const fn new_ele(uid: &'static str, name: &'static str, codec: Codec<D, R, W>) -> Self {
482        TransferSyntax {
483            uid,
484            name,
485            byte_order: Endianness::Little,
486            explicit_vr: true,
487            codec,
488        }
489    }
490
491    /// Obtain this transfer syntax' unique identifier.
492    pub const fn uid(&self) -> &'static str {
493        self.uid
494    }
495
496    /// Obtain the name of this transfer syntax.
497    pub const fn name(&self) -> &'static str {
498        self.name
499    }
500
501    /// Obtain this transfer syntax' expected endianness.
502    pub const fn endianness(&self) -> Endianness {
503        self.byte_order
504    }
505
506    /// Obtain this transfer syntax' codec specification.
507    pub fn codec(&self) -> &Codec<D, R, W> {
508        &self.codec
509    }
510
511    /// Check whether this transfer syntax specifier provides a complete
512    /// implementation,
513    /// meaning that it can both decode and encode in this transfer syntax.
514    pub fn is_fully_supported(&self) -> bool {
515        matches!(
516            self.codec,
517            Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(Some(_), Some(_)),
518        )
519    }
520
521    /// Check whether no codecs are required for this transfer syntax,
522    /// meaning that a complete implementation is available
523    /// and no pixel data conversion is required.
524    pub fn is_codec_free(&self) -> bool {
525        matches!(self.codec, Codec::None)
526    }
527
528    /// Check whether neither reading nor writing of data sets is supported.
529    /// If this is `true`, encoding and decoding will not be available.
530    pub fn is_unsupported(&self) -> bool {
531        matches!(self.codec, Codec::Dataset(None))
532    }
533
534    /// Check whether reading and writing the pixel data is unsupported.
535    /// If this is `true`, encoding and decoding of the data set may still
536    /// be possible, but the pixel data will only be available in its
537    /// encapsulated form.
538    pub fn is_unsupported_pixel_encapsulation(&self) -> bool {
539        matches!(
540            self.codec,
541            Codec::Dataset(None) | Codec::EncapsulatedPixelData(None, None)
542        )
543    }
544
545    /// Check whether this codec can fully decode
546    /// both data sets and pixel data.
547    pub fn can_decode_all(&self) -> bool {
548        matches!(
549            self.codec,
550            Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(Some(_), _)
551        )
552    }
553
554    /// Check whether this codec can decode the data set.
555    pub fn can_decode_dataset(&self) -> bool {
556        matches!(
557            self.codec,
558            Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(..)
559        )
560    }
561
562    /// Retrieve the appropriate data element decoder for this transfer syntax.
563    /// Can yield none if decoding is not supported.
564    ///
565    /// The resulting decoder does not consider pixel data encapsulation or
566    /// data set compression rules. This means that the consumer of this method
567    /// needs to adapt the reader before using the decoder.
568    pub fn decoder<'s>(&self) -> Option<DynDecoder<dyn Read + 's>> {
569        self.decoder_for()
570    }
571
572    /// Retrieve the appropriate data element decoder for this transfer syntax
573    /// and given reader type (this method is not object safe).
574    /// Can yield none if decoding is not supported.
575    ///
576    /// The resulting decoder does not consider pixel data encapsulation or
577    /// data set compression rules. This means that the consumer of this method
578    /// needs to adapt the reader before using the decoder.
579    pub fn decoder_for<S>(&self) -> Option<DynDecoder<S>>
580    where
581        Self: Sized,
582        S: ?Sized + Read,
583    {
584        match (self.byte_order, self.explicit_vr) {
585            (Endianness::Little, false) => Some(Box::<ImplicitVRLittleEndianDecoder<_>>::default()),
586            (Endianness::Little, true) => Some(Box::<ExplicitVRLittleEndianDecoder>::default()),
587            (Endianness::Big, true) => Some(Box::<ExplicitVRBigEndianDecoder>::default()),
588            _ => None,
589        }
590    }
591
592    /// Retrieve the appropriate data element encoder for this transfer syntax.
593    /// Can yield none if encoding is not supported. The resulting encoder does not
594    /// consider pixel data encapsulation or data set compression rules.
595    pub fn encoder<'w>(&self) -> Option<DynEncoder<'w, dyn Write + 'w>> {
596        self.encoder_for()
597    }
598
599    /// Retrieve the appropriate data element encoder for this transfer syntax
600    /// and the given writer type (this method is not object safe).
601    /// Can yield none if encoding is not supported. The resulting encoder does not
602    /// consider pixel data encapsulation or data set compression rules.
603    pub fn encoder_for<'w, T>(&self) -> Option<DynEncoder<'w, T>>
604    where
605        Self: Sized,
606        T: ?Sized + Write + 'w,
607    {
608        match (self.byte_order, self.explicit_vr) {
609            (Endianness::Little, false) => Some(Box::new(EncoderFor::new(
610                ImplicitVRLittleEndianEncoder::default(),
611            ))),
612            (Endianness::Little, true) => Some(Box::new(EncoderFor::new(
613                ExplicitVRLittleEndianEncoder::default(),
614            ))),
615            (Endianness::Big, true) => Some(Box::new(EncoderFor::new(
616                ExplicitVRBigEndianEncoder::default(),
617            ))),
618            _ => None,
619        }
620    }
621
622    /// Obtain a dynamic basic decoder, based on this transfer syntax' expected endianness.
623    pub fn basic_decoder(&self) -> BasicDecoder {
624        BasicDecoder::from(self.endianness())
625    }
626
627    /// Type-erase the pixel data or data set codec.
628    pub fn erased(self) -> TransferSyntax
629    where
630        D: Send + Sync + 'static,
631        D: DataRWAdapter<
632            Box<dyn Read>,
633            Box<dyn Write>,
634            Reader = Box<dyn Read>,
635            Writer = Box<dyn Write>,
636        >,
637        R: Send + Sync + 'static,
638        R: PixelDataReader,
639        W: Send + Sync + 'static,
640        W: PixelDataWriter,
641    {
642        let codec = match self.codec {
643            Codec::Dataset(d) => Codec::Dataset(d.map(|d| Box::new(d) as _)),
644            Codec::EncapsulatedPixelData(r, w) => Codec::EncapsulatedPixelData(
645                r.map(|r| Box::new(r) as _),
646                w.map(|w| Box::new(w) as _),
647            ),
648            Codec::None => Codec::None,
649        };
650
651        TransferSyntax {
652            uid: self.uid,
653            name: self.name,
654            byte_order: self.byte_order,
655            explicit_vr: self.explicit_vr,
656            codec,
657        }
658    }
659}