dicom_object/
file.rs

1use dicom_core::{DataDictionary, Tag};
2use dicom_dictionary_std::StandardDataDictionary;
3use dicom_encoding::transfer_syntax::TransferSyntaxIndex;
4use dicom_transfer_syntax_registry::TransferSyntaxRegistry;
5
6// re-export from dicom_parser
7pub use dicom_parser::dataset::read::OddLengthStrategy;
8
9use crate::{DefaultDicomObject, ReadError};
10use std::io::Read;
11use std::path::Path;
12
13pub type Result<T, E = ReadError> = std::result::Result<T, E>;
14
15/// Create a DICOM object by reading from a byte source.
16///
17/// This function assumes the standard file encoding structure without the
18/// preamble: file meta group, followed by the rest of the data set.
19pub fn from_reader<F>(file: F) -> Result<DefaultDicomObject>
20where
21    F: Read,
22{
23    OpenFileOptions::new().from_reader(file)
24}
25
26/// Create a DICOM object by reading from a file.
27///
28/// This function assumes the standard file encoding structure: 128-byte
29/// preamble, file meta group, and the rest of the data set.
30pub fn open_file<P>(path: P) -> Result<DefaultDicomObject>
31where
32    P: AsRef<Path>,
33{
34    OpenFileOptions::new().open_file(path)
35}
36
37/// A builder type for opening a DICOM file with additional options.
38///
39/// This builder exposes additional properties
40/// to configure the reading of a DICOM file.
41///
42/// # Example
43///
44/// Create a `OpenFileOptions`,
45/// call adaptor methods in a chain,
46/// and finish the operation with
47/// either [`open_file()`](OpenFileOptions::open_file)
48/// or [`from_reader()`](OpenFileOptions::from_reader).
49///
50/// ```no_run
51/// # use dicom_object::OpenFileOptions;
52/// let file = OpenFileOptions::new()
53///     .read_until(dicom_dictionary_std::tags::PIXEL_DATA)
54///     .open_file("path/to/file.dcm")?;
55/// # Result::<(), Box<dyn std::error::Error>>::Ok(())
56/// ```
57#[derive(Debug, Default, Clone)]
58#[non_exhaustive]
59pub struct OpenFileOptions<D = StandardDataDictionary, T = TransferSyntaxRegistry> {
60    data_dictionary: D,
61    ts_index: T,
62    read_until: Option<Tag>,
63    read_preamble: ReadPreamble,
64    odd_length: OddLengthStrategy,
65}
66
67impl OpenFileOptions {
68    pub fn new() -> Self {
69        OpenFileOptions::default()
70    }
71}
72
73impl<D, T> OpenFileOptions<D, T> {
74    /// Set the operation to read only until the given tag is found.
75    ///
76    /// The reading process ends immediately after this tag,
77    /// or any other tag that is next in the standard DICOM tag ordering,
78    /// is found in the object's root data set.
79    /// An element with the exact tag will be excluded from the output.
80    pub fn read_until(mut self, tag: Tag) -> Self {
81        self.read_until = Some(tag);
82        self
83    }
84
85    /// Set the operation to read all elements of the data set to the end.
86    ///
87    /// This is the default behavior.
88    pub fn read_all(mut self) -> Self {
89        self.read_until = None;
90        self
91    }
92
93    /// Set whether to read the 128-byte DICOM file preamble.
94    pub fn read_preamble(mut self, option: ReadPreamble) -> Self {
95        self.read_preamble = option;
96        self
97    }
98
99    /// Set how data elements with an odd length should be handled.
100    pub fn odd_length_strategy(mut self, option: OddLengthStrategy) -> Self {
101        self.odd_length = option;
102        self
103    }
104
105    /// Set the transfer syntax index to use when reading the file.
106    pub fn transfer_syntax_index<Tr>(self, ts_index: Tr) -> OpenFileOptions<D, Tr>
107    where
108        Tr: TransferSyntaxIndex,
109    {
110        OpenFileOptions {
111            data_dictionary: self.data_dictionary,
112            read_until: self.read_until,
113            read_preamble: self.read_preamble,
114            ts_index,
115            odd_length: self.odd_length,
116        }
117    }
118
119    /// Set the transfer syntax index to use when reading the file.
120    #[deprecated(since="0.8.1", note="please use `transfer_syntax_index` instead")]
121    pub fn tranfer_syntax_index<Tr>(self, ts_index: Tr) -> OpenFileOptions<D, Tr>
122    where
123        Tr: TransferSyntaxIndex,
124    {
125        self.transfer_syntax_index(ts_index)
126    }
127
128    /// Set the data element dictionary to use when reading the file.
129    pub fn dictionary<Di>(self, dict: Di) -> OpenFileOptions<Di, T>
130    where
131        Di: DataDictionary,
132        Di: Clone,
133    {
134        OpenFileOptions {
135            data_dictionary: dict,
136            read_until: self.read_until,
137            read_preamble: self.read_preamble,
138            ts_index: self.ts_index,
139            odd_length: self.odd_length,
140        }
141    }
142
143    /// Open the file at the given path.
144    pub fn open_file<P>(self, path: P) -> Result<DefaultDicomObject<D>>
145    where
146        P: AsRef<Path>,
147        D: DataDictionary,
148        D: Clone,
149        T: TransferSyntaxIndex,
150    {
151        DefaultDicomObject::open_file_with_all_options(
152            path,
153            self.data_dictionary,
154            self.ts_index,
155            self.read_until,
156            self.read_preamble,
157            self.odd_length,
158        )
159    }
160
161    /// Obtain a DICOM object by reading from a byte source.
162    ///
163    /// This method assumes
164    /// the standard file encoding structure without the preamble:
165    /// file meta group, followed by the rest of the data set.
166    pub fn from_reader<R>(self, from: R) -> Result<DefaultDicomObject<D>>
167    where
168        R: Read,
169        D: DataDictionary,
170        D: Clone,
171        T: TransferSyntaxIndex,
172    {
173        DefaultDicomObject::from_reader_with_all_options(
174            from,
175            self.data_dictionary,
176            self.ts_index,
177            self.read_until,
178            self.read_preamble,
179            self.odd_length,
180        )
181    }
182}
183
184/// An enumerate of supported options for
185/// whether to read the 128-byte DICOM file preamble.
186#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
187pub enum ReadPreamble {
188    /// Try to detect the presence of the preamble automatically.
189    /// If detection fails, it will revert to always reading the preamble
190    /// when opening a file by path,
191    /// and not reading it when reading from a byte source.
192    #[default]
193    Auto,
194    /// Never read the preamble,
195    /// thus assuming that the original source does not have it.
196    Never,
197    /// Always read the preamble first,
198    /// thus assuming that the original source always has it.
199    Always,
200}