dicom_toolkit_data/
file_format.rs1use crate::dataset::DataSet;
7use crate::meta_info::FileMetaInformation;
8use dicom_toolkit_core::error::DcmResult;
9use std::path::Path;
10
11#[derive(Debug, Clone)]
13pub struct FileFormat {
14 pub meta: FileMetaInformation,
15 pub dataset: DataSet,
16}
17
18impl FileFormat {
19 pub fn new(meta: FileMetaInformation, dataset: DataSet) -> Self {
20 Self { meta, dataset }
21 }
22
23 pub fn from_dataset(sop_class_uid: &str, sop_instance_uid: &str, dataset: DataSet) -> Self {
27 let meta = FileMetaInformation::new(sop_class_uid, sop_instance_uid, "1.2.840.10008.1.2.1");
28 Self { meta, dataset }
29 }
30
31 pub fn open(path: impl AsRef<Path>) -> DcmResult<Self> {
33 let data = std::fs::read(path.as_ref())?;
34 crate::io::reader::parse_file(&data)
35 }
36
37 pub fn save(&self, path: impl AsRef<Path>) -> DcmResult<()> {
39 let bytes = crate::io::writer::encode_file(self)?;
40 std::fs::write(path.as_ref(), &bytes)?;
41 Ok(())
42 }
43
44 pub fn save_as(&self, path: impl AsRef<Path>, ts_uid: &str) -> DcmResult<()> {
49 let mut ff = self.clone();
50 ff.meta.transfer_syntax_uid = ts_uid.to_string();
51 let bytes = crate::io::writer::encode_file(&ff)?;
52 std::fs::write(path.as_ref(), &bytes)?;
53 Ok(())
54 }
55}
56
57#[cfg(test)]
60mod tests {
61 use super::*;
62 use crate::element::Element;
63 use crate::io::reader::DicomReader;
64 use crate::io::writer::DicomWriter;
65 use dicom_toolkit_dict::{tags, Vr};
66
67 fn make_test_dataset() -> DataSet {
68 let mut ds = DataSet::new();
69 ds.insert(Element::string(tags::PATIENT_NAME, Vr::PN, "Smith^John"));
70 ds.insert(Element::u16(tags::ROWS, 512));
71 ds.insert(Element::u16(tags::COLUMNS, 256));
72 ds
73 }
74
75 #[test]
76 fn file_format_roundtrip_explicit_vr_le() {
77 let ds = make_test_dataset();
78 let ff = FileFormat::from_dataset("1.2.840.10008.5.1.4.1.1.2", "1.2.3.4.5", ds.clone());
79
80 let mut buf = Vec::new();
81 DicomWriter::new(&mut buf).write_file(&ff).unwrap();
82
83 let ff2 = DicomReader::new(buf.as_slice()).read_file().unwrap();
84 assert_eq!(ff2.dataset.get_u16(tags::ROWS), Some(512));
85 assert_eq!(ff2.dataset.get_u16(tags::COLUMNS), Some(256));
86 assert_eq!(
87 ff2.dataset.get_string(tags::PATIENT_NAME),
88 Some("Smith^John")
89 );
90 }
91
92 #[test]
93 fn file_format_roundtrip_implicit_vr_le() {
94 let mut ds = DataSet::new();
95 ds.insert(Element::u16(tags::ROWS, 128));
96 ds.insert(Element::u16(tags::COLUMNS, 128));
97
98 let mut buf = Vec::new();
99 DicomWriter::new(&mut buf)
100 .write_dataset(&ds, "1.2.840.10008.1.2")
101 .unwrap();
102
103 let ds2 = DicomReader::new(buf.as_slice())
104 .read_dataset("1.2.840.10008.1.2")
105 .unwrap();
106 assert_eq!(ds2.get_u16(tags::ROWS), Some(128));
107 assert_eq!(ds2.get_u16(tags::COLUMNS), Some(128));
108 }
109
110 #[test]
111 fn file_format_roundtrip_with_sequence() {
112 let mut item = DataSet::new();
113 item.insert(Element::string(tags::PATIENT_ID, Vr::LO, "PID001"));
114
115 let mut ds = DataSet::new();
116 ds.insert(Element::sequence(tags::REFERENCED_SOP_SEQUENCE, vec![item]));
117
118 let ff = FileFormat::from_dataset("", "", ds);
119 let mut buf = Vec::new();
120 DicomWriter::new(&mut buf).write_file(&ff).unwrap();
121
122 let ff2 = DicomReader::new(buf.as_slice()).read_file().unwrap();
123 let items = ff2
124 .dataset
125 .get_items(tags::REFERENCED_SOP_SEQUENCE)
126 .unwrap();
127 assert_eq!(items.len(), 1);
128 assert_eq!(items[0].get_string(tags::PATIENT_ID), Some("PID001"));
129 }
130
131 #[test]
132 fn file_format_from_disk_roundtrip() {
133 let dir = tempfile::tempdir().unwrap();
134 let path = dir.path().join("test.dcm");
135
136 let ds = make_test_dataset();
137 let ff = FileFormat::from_dataset("", "1.2.3", ds);
138 ff.save(&path).unwrap();
139
140 let loaded = FileFormat::open(&path).unwrap();
141 assert_eq!(loaded.dataset.get_u16(tags::ROWS), Some(512));
142 assert_eq!(
143 loaded.dataset.get_string(tags::PATIENT_NAME),
144 Some("Smith^John")
145 );
146 }
147
148 #[test]
149 fn file_format_save_as_different_ts() {
150 let dir = tempfile::tempdir().unwrap();
151 let path1 = dir.path().join("explicit.dcm");
152
153 let ds = make_test_dataset();
154 let ff = FileFormat::from_dataset("", "1.2.3", ds);
155 ff.save_as(&path1, "1.2.840.10008.1.2").unwrap();
156
157 let loaded = FileFormat::open(&path1).unwrap();
158 assert_eq!(loaded.meta.transfer_syntax_uid, "1.2.840.10008.1.2");
159 }
160
161 #[test]
162 fn file_format_meta_generated() {
163 let ff = FileFormat::from_dataset("1.2.840.10008.5.1.4.1.1.2", "9.8.7.6.5", DataSet::new());
164 assert_eq!(ff.meta.transfer_syntax_uid, "1.2.840.10008.1.2.1");
165 assert_eq!(
166 ff.meta.media_storage_sop_class_uid,
167 "1.2.840.10008.5.1.4.1.1.2"
168 );
169 assert_eq!(ff.meta.media_storage_sop_instance_uid, "9.8.7.6.5");
170 }
171}