Skip to main content

dicom_encoding/encode/
mod.rs

1//! This module contains all DICOM data element encoding logic.
2use byteordered::Endianness;
3use dicom_core::value::serialize::{encode_date, encode_datetime, encode_time};
4use dicom_core::{DataElementHeader, PrimitiveValue, Tag};
5use snafu::{Backtrace, ResultExt, Snafu};
6use std::fmt;
7use std::io::{self, Write};
8use std::marker::PhantomData;
9
10pub mod basic;
11pub mod explicit_be;
12pub mod explicit_le;
13pub mod implicit_le;
14
15/// Module-level error type:
16/// for errors which may occur while encoding DICOM data.
17#[derive(Debug, Snafu)]
18#[non_exhaustive]
19pub enum Error {
20    #[snafu(display("Failed to write Date value"))]
21    WriteDate {
22        backtrace: Backtrace,
23        source: io::Error,
24    },
25    #[snafu(display("Failed to write Time value"))]
26    WriteTime {
27        backtrace: Backtrace,
28        source: io::Error,
29    },
30    #[snafu(display("Failed to write DateTime value"))]
31    WriteDateTime {
32        backtrace: Backtrace,
33        source: io::Error,
34    },
35    #[snafu(display("Failed to write tag"))]
36    WriteTag {
37        backtrace: Backtrace,
38        source: io::Error,
39    },
40    #[snafu(display("Failed to write tag group"))]
41    WriteTagGroup {
42        backtrace: Backtrace,
43        source: io::Error,
44    },
45    #[snafu(display("Failed to write tag element"))]
46    WriteTagElement {
47        backtrace: Backtrace,
48        source: io::Error,
49    },
50    #[snafu(display("Failed to write item header"))]
51    WriteItemHeader {
52        backtrace: Backtrace,
53        source: io::Error,
54    },
55    #[snafu(display("Failed to write element header"))]
56    WriteHeader {
57        backtrace: Backtrace,
58        source: io::Error,
59    },
60    #[snafu(display("Failed to write item delimiter"))]
61    WriteItemDelimiter {
62        backtrace: Backtrace,
63        source: io::Error,
64    },
65    #[snafu(display("Failed to write sequence delimiter"))]
66    WriteSequenceDelimiter {
67        backtrace: Backtrace,
68        source: io::Error,
69    },
70    #[snafu(display("Failed to write {} value", typ))]
71    WriteBinary {
72        typ: &'static str,
73        backtrace: Backtrace,
74        source: io::Error,
75    },
76    #[snafu(display("Failed to write string value"))]
77    WriteString {
78        backtrace: Backtrace,
79        source: io::Error,
80    },
81    #[snafu(display("Failed to write bytes"))]
82    WriteBytes {
83        backtrace: Backtrace,
84        source: io::Error,
85    },
86    #[snafu(display("Failed to write pixel data offset table"))]
87    WriteOffsetTable {
88        backtrace: Backtrace,
89        source: io::Error,
90    },
91    #[snafu(display("Item too long ({} bytes) for a 16-bit length", length))]
92    WriteHeaderTooLong { length: u32, backtrace: Backtrace },
93}
94
95pub type Result<T, E = Error> = std::result::Result<T, E>;
96
97/// Type trait for an encoder of basic data properties.
98/// Unlike `Encode` (and similar to `BasicDecode`), this trait is not object
99/// safe because it's better to just provide a dynamic implementation.
100pub trait BasicEncode {
101    /// Retrieve the encoder's endianness.
102    fn endianness(&self) -> Endianness;
103
104    /// Encode an unsigned short value to the given writer.
105    fn encode_us<W>(&self, to: W, value: u16) -> io::Result<()>
106    where
107        W: Write;
108
109    /// Encode an unsigned long value to the given writer.
110    fn encode_ul<W>(&self, to: W, value: u32) -> io::Result<()>
111    where
112        W: Write;
113
114    /// Encode an unsigned very long value to the given writer.
115    fn encode_uv<W>(&self, to: W, value: u64) -> io::Result<()>
116    where
117        W: Write;
118
119    /// Encode a signed short value to the given writer.
120    fn encode_ss<W>(&self, to: W, value: i16) -> io::Result<()>
121    where
122        W: Write;
123
124    /// Encode a signed long value to the given writer.
125    fn encode_sl<W>(&self, to: W, value: i32) -> io::Result<()>
126    where
127        W: Write;
128
129    /// Encode a signed very long value to the given writer.
130    fn encode_sv<W>(&self, to: W, value: i64) -> io::Result<()>
131    where
132        W: Write;
133
134    /// Encode a single precision float value to the given writer.
135    fn encode_fl<W>(&self, to: W, value: f32) -> io::Result<()>
136    where
137        W: Write;
138
139    /// Encode a double precision float value to the given writer.
140    fn encode_fd<W>(&self, to: W, value: f64) -> io::Result<()>
141    where
142        W: Write;
143
144    /// If this encoder is in Little Endian, evaluate the first function.
145    /// Otherwise, evaluate the second one.
146    #[inline]
147    fn with_encoder<T, F1, F2>(&self, f_le: F1, f_be: F2) -> T
148    where
149        F1: FnOnce(basic::LittleEndianBasicEncoder) -> T,
150        F2: FnOnce(basic::BigEndianBasicEncoder) -> T,
151    {
152        match self.endianness() {
153            Endianness::Little => f_le(basic::LittleEndianBasicEncoder),
154            Endianness::Big => f_be(basic::BigEndianBasicEncoder),
155        }
156    }
157
158    /// Encode a primitive value to the given writer. The default implementation
159    /// delegates to the other value encoding methods.
160    fn encode_primitive<W>(&self, mut to: W, value: &PrimitiveValue) -> Result<usize>
161    where
162        W: Write,
163    {
164        use PrimitiveValue::*;
165        match value {
166            Empty => Ok(0), // no-op
167            Date(date) => {
168                encode_collection_delimited(&mut to, date, |to, date| encode_date(to, *date))
169                    .context(WriteDateSnafu)
170            }
171            Time(time) => {
172                encode_collection_delimited(&mut to, time, |to, time| encode_time(to, *time))
173                    .context(WriteTimeSnafu)
174            }
175            DateTime(datetime) => encode_collection_delimited(&mut to, datetime, |to, datetime| {
176                encode_datetime(to, *datetime)
177            })
178            .context(WriteDateTimeSnafu),
179            Str(s) => {
180                // Note: this will always print in UTF-8. Consumers should
181                // intercept string primitive values and encode them according
182                // to the expected character set.
183                write!(to, "{s}").context(WriteStringSnafu)?;
184                Ok(s.len())
185            }
186            Strs(s) => encode_collection_delimited(&mut to, s, |to, s| {
187                // Note: this will always print in UTF-8. Consumers should
188                // intercept string primitive values and encode them according
189                // to the expected character set.
190                write!(to, "{s}")?;
191                Ok(s.len())
192            })
193            .context(WriteStringSnafu),
194            F32(values) => {
195                for v in values {
196                    self.encode_fl(&mut to, *v)
197                        .context(WriteBinarySnafu { typ: "F32" })?;
198                }
199                Ok(values.len() * 4)
200            }
201            F64(values) => {
202                for v in values {
203                    self.encode_fd(&mut to, *v)
204                        .context(WriteBinarySnafu { typ: "F64" })?;
205                }
206                Ok(values.len() * 8)
207            }
208            U64(values) => {
209                for v in values {
210                    self.encode_uv(&mut to, *v)
211                        .context(WriteBinarySnafu { typ: "U64" })?;
212                }
213                Ok(values.len() * 8)
214            }
215            I64(values) => {
216                for v in values {
217                    self.encode_sv(&mut to, *v)
218                        .context(WriteBinarySnafu { typ: "I64" })?;
219                }
220                Ok(values.len() * 8)
221            }
222            U32(values) => {
223                for v in values {
224                    self.encode_ul(&mut to, *v)
225                        .context(WriteBinarySnafu { typ: "U32" })?;
226                }
227                Ok(values.len() * 4)
228            }
229            I32(values) => {
230                for v in values {
231                    self.encode_sl(&mut to, *v)
232                        .context(WriteBinarySnafu { typ: "I32" })?;
233                }
234                Ok(values.len() * 4)
235            }
236            U16(values) => {
237                for v in values {
238                    self.encode_us(&mut to, *v)
239                        .context(WriteBinarySnafu { typ: "U16" })?;
240                }
241                Ok(values.len() * 2)
242            }
243            I16(values) => {
244                for v in values {
245                    self.encode_ss(&mut to, *v)
246                        .context(WriteBinarySnafu { typ: "I16" })?;
247                }
248                Ok(values.len() * 2)
249            }
250            U8(values) => {
251                to.write_all(values).context(WriteBytesSnafu)?;
252                Ok(values.len())
253            }
254            Tags(tags) => {
255                for tag in tags {
256                    self.encode_us(&mut to, tag.0).context(WriteTagGroupSnafu)?;
257                    self.encode_us(&mut to, tag.1)
258                        .context(WriteTagElementSnafu)?;
259                }
260                Ok(tags.len() * 4)
261            }
262        }
263    }
264}
265
266fn encode_collection_delimited<W, T, F>(
267    to: &mut W,
268    col: &[T],
269    mut encode_element_fn: F,
270) -> io::Result<usize>
271where
272    W: ?Sized + Write,
273    F: FnMut(&mut W, &T) -> io::Result<usize>,
274{
275    let mut acc = 0;
276    for (i, v) in col.iter().enumerate() {
277        acc += encode_element_fn(to, v)?;
278        if i < col.len() - 1 {
279            to.write_all(b"\\")?;
280            acc += 1;
281        }
282    }
283    Ok(acc)
284}
285
286/// Type trait for a data element encoder.
287pub trait Encode {
288    /// Encode and write an element tag.
289    fn encode_tag<W>(&self, to: W, tag: Tag) -> Result<()>
290    where
291        W: Write;
292
293    /// Encode and write a data element header to the given destination.
294    /// Returns the number of bytes effectively written on success.
295    fn encode_element_header<W>(&self, to: W, de: DataElementHeader) -> Result<usize>
296    where
297        W: Write;
298
299    /// Encode and write a DICOM sequence item header to the given destination.
300    /* Although item element headers are always a tag and length sequence regardless of TS,
301    the encoding of the length is unknown at this level. So no default impl. */
302    fn encode_item_header<W>(&self, to: W, len: u32) -> Result<()>
303    where
304        W: Write;
305
306    /// Encode and write a DICOM sequence item delimiter to the given destination.
307    fn encode_item_delimiter<W>(&self, mut to: W) -> Result<()>
308    where
309        W: Write,
310    {
311        self.encode_tag(&mut to, Tag(0xFFFE, 0xE00D))?;
312        to.write_all(&[0u8; 4]).context(WriteItemDelimiterSnafu)?;
313        Ok(())
314    }
315
316    /// Encode and write a DICOM sequence delimiter to the given destination.
317    fn encode_sequence_delimiter<W>(&self, mut to: W) -> Result<()>
318    where
319        W: Write,
320    {
321        self.encode_tag(&mut to, Tag(0xFFFE, 0xE0DD))?;
322        to.write_all(&[0u8; 4])
323            .context(WriteSequenceDelimiterSnafu)?;
324        Ok(())
325    }
326
327    /// Encode and write a primitive DICOM value to the given destination.
328    fn encode_primitive<W>(&self, to: W, value: &PrimitiveValue) -> Result<usize>
329    where
330        W: Write;
331
332    /// Encode and write a DICOM pixel data offset table
333    /// to the given destination.
334    ///
335    /// For convenience, returns the number of bytes written on success,
336    /// equivalent to `offset_table.len() * 4`.
337    // Note that offset tables might not apply to all forms of encoding,
338    // but this method needs to exist nevertheless.
339    fn encode_offset_table<W>(&self, to: W, offset_table: &[u32]) -> Result<usize>
340    where
341        W: Write;
342}
343
344impl<T: ?Sized> Encode for &T
345where
346    T: Encode,
347{
348    fn encode_tag<W>(&self, to: W, tag: Tag) -> Result<()>
349    where
350        W: Write,
351    {
352        (**self).encode_tag(to, tag)
353    }
354
355    fn encode_element_header<W>(&self, to: W, de: DataElementHeader) -> Result<usize>
356    where
357        W: Write,
358    {
359        (**self).encode_element_header(to, de)
360    }
361
362    fn encode_item_header<W>(&self, to: W, len: u32) -> Result<()>
363    where
364        W: Write,
365    {
366        (**self).encode_item_header(to, len)
367    }
368
369    fn encode_item_delimiter<W>(&self, to: W) -> Result<()>
370    where
371        W: Write,
372    {
373        (**self).encode_item_delimiter(to)
374    }
375
376    fn encode_sequence_delimiter<W>(&self, to: W) -> Result<()>
377    where
378        W: Write,
379    {
380        (**self).encode_sequence_delimiter(to)
381    }
382
383    fn encode_primitive<W>(&self, to: W, value: &PrimitiveValue) -> Result<usize>
384    where
385        W: Write,
386    {
387        (**self).encode_primitive(to, value)
388    }
389
390    fn encode_offset_table<W>(&self, to: W, offset_table: &[u32]) -> Result<usize>
391    where
392        W: Write,
393    {
394        (**self).encode_offset_table(to, offset_table)
395    }
396}
397
398impl<T: ?Sized> Encode for Box<T>
399where
400    T: Encode,
401{
402    fn encode_tag<W>(&self, to: W, tag: Tag) -> Result<()>
403    where
404        W: Write,
405    {
406        (**self).encode_tag(to, tag)
407    }
408
409    fn encode_element_header<W>(&self, to: W, de: DataElementHeader) -> Result<usize>
410    where
411        W: Write,
412    {
413        (**self).encode_element_header(to, de)
414    }
415
416    fn encode_item_header<W>(&self, to: W, len: u32) -> Result<()>
417    where
418        W: Write,
419    {
420        (**self).encode_item_header(to, len)
421    }
422
423    fn encode_item_delimiter<W>(&self, to: W) -> Result<()>
424    where
425        W: Write,
426    {
427        (**self).encode_item_delimiter(to)
428    }
429
430    fn encode_sequence_delimiter<W>(&self, to: W) -> Result<()>
431    where
432        W: Write,
433    {
434        (**self).encode_sequence_delimiter(to)
435    }
436
437    fn encode_primitive<W>(&self, to: W, value: &PrimitiveValue) -> Result<usize>
438    where
439        W: Write,
440    {
441        (**self).encode_primitive(to, value)
442    }
443
444    fn encode_offset_table<W>(&self, to: W, offset_table: &[u32]) -> Result<usize>
445    where
446        W: Write,
447    {
448        (**self).encode_offset_table(to, offset_table)
449    }
450}
451
452/// Type trait for a data element encoder to a single known writer type `W`.
453pub trait EncodeTo<W: ?Sized> {
454    /// Encode and write an element tag.
455    fn encode_tag(&self, to: &mut W, tag: Tag) -> Result<()>
456    where
457        W: Write;
458
459    /// Encode and write a data element header to the given destination.
460    /// Returns the number of bytes effectively written on success.
461    ///
462    /// Note that data element header should be encoded as is,
463    /// regardless of the given value length.
464    /// Any eventual padding logic should be done at a higher level.
465    fn encode_element_header(&self, to: &mut W, de: DataElementHeader) -> Result<usize>
466    where
467        W: Write;
468
469    /// Encode and write a DICOM sequence item header to the given destination.
470    /* Although item element headers are always a tag and length sequence regardless of TS,
471    the encoding of the length is unknown at this level. So no default impl. */
472    fn encode_item_header(&self, to: &mut W, len: u32) -> Result<()>
473    where
474        W: Write;
475
476    /// Encode and write a DICOM sequence item delimiter to the given destination.
477    fn encode_item_delimiter(&self, to: &mut W) -> Result<()>
478    where
479        W: Write;
480
481    /// Encode and write a DICOM sequence delimiter to the given destination.
482    fn encode_sequence_delimiter(&self, to: &mut W) -> Result<()>
483    where
484        W: Write;
485
486    /// Encode and write a primitive DICOM value to the given destination.
487    fn encode_primitive(&self, to: &mut W, value: &PrimitiveValue) -> Result<usize>
488    where
489        W: Write;
490
491    /// Encode and write a DICOM pixel data offset table
492    /// to the given destination.
493    ///
494    /// For convenience, returns the number of bytes written on success,
495    /// equivalent to `offset_table.len() * 4`.
496    // Note that offset tables might not apply to all forms of encoding,
497    // but this method needs to exist nevertheless.
498    fn encode_offset_table(&self, to: &mut W, offset_table: &[u32]) -> Result<usize>
499    where
500        W: Write;
501}
502
503impl<T, W: ?Sized> EncodeTo<W> for &T
504where
505    T: EncodeTo<W>,
506{
507    fn encode_tag(&self, to: &mut W, tag: Tag) -> Result<()>
508    where
509        W: Write,
510    {
511        (**self).encode_tag(to, tag)
512    }
513
514    fn encode_element_header(&self, to: &mut W, de: DataElementHeader) -> Result<usize>
515    where
516        W: Write,
517    {
518        (**self).encode_element_header(to, de)
519    }
520
521    fn encode_item_header(&self, to: &mut W, len: u32) -> Result<()>
522    where
523        W: Write,
524    {
525        (**self).encode_item_header(to, len)
526    }
527
528    fn encode_item_delimiter(&self, to: &mut W) -> Result<()>
529    where
530        W: Write,
531    {
532        (**self).encode_item_delimiter(to)
533    }
534
535    fn encode_sequence_delimiter(&self, to: &mut W) -> Result<()>
536    where
537        W: Write,
538    {
539        (**self).encode_sequence_delimiter(to)
540    }
541
542    /// Encode and write a primitive DICOM value to the given destination.
543    fn encode_primitive(&self, to: &mut W, value: &PrimitiveValue) -> Result<usize>
544    where
545        W: Write,
546    {
547        (**self).encode_primitive(to, value)
548    }
549
550    fn encode_offset_table(&self, to: &mut W, offset_table: &[u32]) -> Result<usize>
551    where
552        W: Write,
553    {
554        (**self).encode_offset_table(to, offset_table)
555    }
556}
557
558impl<T: ?Sized, W: ?Sized> EncodeTo<W> for Box<T>
559where
560    T: EncodeTo<W>,
561{
562    fn encode_tag(&self, to: &mut W, tag: Tag) -> Result<()>
563    where
564        W: Write,
565    {
566        (**self).encode_tag(to, tag)
567    }
568
569    fn encode_element_header(&self, to: &mut W, de: DataElementHeader) -> Result<usize>
570    where
571        W: Write,
572    {
573        (**self).encode_element_header(to, de)
574    }
575
576    fn encode_item_header(&self, to: &mut W, len: u32) -> Result<()>
577    where
578        W: Write,
579    {
580        (**self).encode_item_header(to, len)
581    }
582
583    fn encode_item_delimiter(&self, to: &mut W) -> Result<()>
584    where
585        W: Write,
586    {
587        (**self).encode_item_delimiter(to)
588    }
589
590    fn encode_sequence_delimiter(&self, to: &mut W) -> Result<()>
591    where
592        W: Write,
593    {
594        (**self).encode_sequence_delimiter(to)
595    }
596
597    /// Encode and write a primitive DICOM value to the given destination.
598    fn encode_primitive(&self, to: &mut W, value: &PrimitiveValue) -> Result<usize>
599    where
600        W: Write,
601    {
602        (**self).encode_primitive(to, value)
603    }
604
605    fn encode_offset_table(&self, to: &mut W, offset_table: &[u32]) -> Result<usize>
606    where
607        W: Write,
608    {
609        (**self).encode_offset_table(to, offset_table)
610    }
611}
612
613/// A type binding of an encoder to a target writer.
614pub struct EncoderFor<T, W: ?Sized> {
615    inner: T,
616    phantom: PhantomData<W>,
617}
618
619impl<T, W: ?Sized> EncoderFor<T, W> {
620    /** Using a generic encoder, create a new encoder specifically for the given
621     * writer of type `W`.
622     */
623    pub fn new(encoder: T) -> Self {
624        EncoderFor {
625            inner: encoder,
626            phantom: PhantomData,
627        }
628    }
629}
630
631impl<T: fmt::Debug, W: ?Sized> fmt::Debug for EncoderFor<T, W> {
632    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
633        f.debug_struct("ImplicitVRLittleEndianEncoder")
634            .field("inner", &self.inner)
635            .field("phantom", &self.phantom)
636            .finish()
637    }
638}
639
640impl<T, W: ?Sized> Default for EncoderFor<T, W>
641where
642    T: Default,
643{
644    fn default() -> Self {
645        EncoderFor {
646            inner: T::default(),
647            phantom: PhantomData,
648        }
649    }
650}
651
652impl<T, W: ?Sized> BasicEncode for EncoderFor<T, W>
653where
654    T: BasicEncode,
655    W: Write,
656{
657    fn endianness(&self) -> Endianness {
658        self.inner.endianness()
659    }
660
661    fn encode_us<S>(&self, to: S, value: u16) -> io::Result<()>
662    where
663        S: Write,
664    {
665        self.inner.encode_us(to, value)
666    }
667
668    fn encode_ul<S>(&self, to: S, value: u32) -> io::Result<()>
669    where
670        S: Write,
671    {
672        self.inner.encode_ul(to, value)
673    }
674
675    fn encode_uv<S>(&self, to: S, value: u64) -> io::Result<()>
676    where
677        S: Write,
678    {
679        self.inner.encode_uv(to, value)
680    }
681
682    fn encode_ss<S>(&self, to: S, value: i16) -> io::Result<()>
683    where
684        S: Write,
685    {
686        self.inner.encode_ss(to, value)
687    }
688
689    fn encode_sl<S>(&self, to: S, value: i32) -> io::Result<()>
690    where
691        S: Write,
692    {
693        self.inner.encode_sl(to, value)
694    }
695
696    fn encode_sv<S>(&self, to: S, value: i64) -> io::Result<()>
697    where
698        S: Write,
699    {
700        self.inner.encode_sv(to, value)
701    }
702
703    fn encode_fl<S>(&self, to: S, value: f32) -> io::Result<()>
704    where
705        S: Write,
706    {
707        self.inner.encode_fl(to, value)
708    }
709
710    fn encode_fd<S>(&self, to: S, value: f64) -> io::Result<()>
711    where
712        S: Write,
713    {
714        self.inner.encode_fd(to, value)
715    }
716}
717
718impl<T, W: ?Sized> EncodeTo<W> for EncoderFor<T, W>
719where
720    T: Encode,
721    W: Write,
722{
723    fn encode_tag(&self, to: &mut W, tag: Tag) -> Result<()> {
724        self.inner.encode_tag(to, tag)
725    }
726
727    fn encode_element_header(&self, to: &mut W, de: DataElementHeader) -> Result<usize> {
728        self.inner.encode_element_header(to, de)
729    }
730
731    fn encode_item_header(&self, to: &mut W, len: u32) -> Result<()> {
732        self.inner.encode_item_header(to, len)
733    }
734
735    fn encode_item_delimiter(&self, to: &mut W) -> Result<()> {
736        self.inner.encode_item_delimiter(to)
737    }
738
739    fn encode_sequence_delimiter(&self, to: &mut W) -> Result<()> {
740        self.inner.encode_sequence_delimiter(to)
741    }
742
743    fn encode_primitive(&self, to: &mut W, value: &PrimitiveValue) -> Result<usize> {
744        self.inner.encode_primitive(to, value)
745    }
746
747    fn encode_offset_table(&self, to: &mut W, offset_table: &[u32]) -> Result<usize> {
748        self.inner.encode_offset_table(to, offset_table)
749    }
750}
751
752#[cfg(test)]
753mod tests {
754    use super::*;
755
756    fn is_encode<T: Encode>(_encoder: &T) {}
757    fn is_encode_to<W: ?Sized, T: EncodeTo<W>>(_encoder: &T) {}
758
759    #[allow(unused)]
760    fn boxed_encode_is_encode<T>(encoder: T)
761    where
762        T: Encode,
763        T: Copy,
764    {
765        is_encode(&encoder);
766        is_encode_to::<dyn Write, _>(&EncoderFor::new(encoder));
767        let boxed = Box::new(encoder);
768        is_encode(&boxed);
769        is_encode_to::<dyn Write, _>(&EncoderFor::new(boxed));
770    }
771}