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