34 {
36
37
38
39
40
41
42
43
44
46
47 std::cout << "DICOM tags are the fundamental identifiers for data elements.\n";
48 std::cout << "Each tag is a (Group, Element) pair of 16-bit hexadecimal numbers.\n\n";
49
50
53
54 std::cout <<
"Patient Name Tag: " << patient_name_tag.
to_string() <<
"\n";
55 std::cout << " Group: 0x" << std::hex << std::setw(4) << std::setfill('0')
56 << patient_name_tag.group() << std::dec << "\n";
57 std::cout << " Element: 0x" << std::hex << std::setw(4) << std::setfill('0')
58 << patient_name_tag.element() << std::dec << "\n";
59 std::cout << " Private? " << (patient_name_tag.is_private() ? "Yes" : "No") << "\n\n";
60
61
62 auto parsed = core::dicom_tag::from_string("(0008,0020)");
63 if (parsed) {
64 std::cout << "Parsed Study Date tag from string: " << parsed->to_string() << "\n";
65 }
66
67
68 std::cout << "\nTag comparison:\n";
69 std::cout << " (0010,0010) == tags::patient_name? "
70 << (patient_name_tag == tags::patient_name ? "Yes" : "No") << "\n";
71
73
74
75
76
77
78
79
81
82 std::cout << "A DICOM dataset is an ordered collection of data elements.\n";
83 std::cout << "Each element consists of: Tag + VR + Value\n\n";
84
85 std::cout << "Common VR (Value Representation) types:\n";
86 std::cout << " PN = Person Name DA = Date TM = Time\n";
87 std::cout << " LO = Long String SH = Short String CS = Code String\n";
88 std::cout << " UI = Unique ID US = Unsigned Short IS = Integer String\n\n";
89
91
92
93
94 dataset.
set_string(tags::patient_name, enc::vr_type::PN,
"DOE^JOHN^M");
95 dataset.
set_string(tags::patient_id, enc::vr_type::LO,
"PAT001");
96 dataset.
set_string(tags::patient_birth_date, enc::vr_type::DA,
"19850315");
97 dataset.
set_string(tags::patient_sex, enc::vr_type::CS,
"M");
98
99
100 dataset.
set_string(tags::study_date, enc::vr_type::DA,
"20240115");
101 dataset.
set_string(tags::study_time, enc::vr_type::TM,
"143022");
102 dataset.
set_string(tags::study_description, enc::vr_type::LO,
"CT CHEST W/CONTRAST");
103 dataset.
set_string(tags::accession_number, enc::vr_type::SH,
"ACC123456");
104
105
106 dataset.
set_string(tags::modality, enc::vr_type::CS,
"CT");
107 dataset.
set_string(tags::series_description, enc::vr_type::LO,
"AXIAL 3mm");
108 dataset.
set_numeric<uint32_t>(tags::series_number, enc::vr_type::IS, 1);
109 dataset.
set_numeric<uint32_t>(tags::instance_number, enc::vr_type::IS, 1);
110
111
112
113 dataset.
set_string(tags::study_instance_uid, enc::vr_type::UI,
114 "1.2.410.200001.1.1.20240115.143022.1");
115 dataset.
set_string(tags::series_instance_uid, enc::vr_type::UI,
116 "1.2.410.200001.1.1.20240115.143022.1.1");
117 dataset.
set_string(tags::sop_class_uid, enc::vr_type::UI,
118 "1.2.840.10008.5.1.4.1.1.2");
119 dataset.
set_string(tags::sop_instance_uid, enc::vr_type::UI,
120 "1.2.410.200001.1.1.20240115.143022.1.1.1");
121
122
123
124 dataset.
set_numeric<uint16_t>(tags::rows, enc::vr_type::US, 512);
125 dataset.
set_numeric<uint16_t>(tags::columns, enc::vr_type::US, 512);
126 dataset.
set_numeric<uint16_t>(tags::bits_allocated, enc::vr_type::US, 16);
127 dataset.
set_numeric<uint16_t>(tags::bits_stored, enc::vr_type::US, 12);
128 dataset.
set_numeric<uint16_t>(tags::high_bit, enc::vr_type::US, 11);
129 dataset.
set_numeric<uint16_t>(tags::pixel_representation, enc::vr_type::US, 0);
130 dataset.
set_numeric<uint16_t>(tags::samples_per_pixel, enc::vr_type::US, 1);
131 dataset.
set_string(tags::photometric_interpretation, enc::vr_type::CS,
"MONOCHROME2");
132
133
134 std::cout <<
"Dataset created with " << dataset.
size() <<
" elements:\n\n";
135
137 {
"Name", dataset.
get_string(tags::patient_name)},
139 {
"Birth Date", dataset.
get_string(tags::patient_birth_date)},
140 {
"Sex", dataset.
get_string(tags::patient_sex)}
141 });
142
144 {
"Date", dataset.
get_string(tags::study_date)},
145 {
"Description", dataset.
get_string(tags::study_description)},
146 {
"Modality", dataset.
get_string(tags::modality)},
147 {
"Accession", dataset.
get_string(tags::accession_number)}
148 });
149
150
151 auto rows_val = dataset.
get_numeric<uint16_t>(tags::rows);
152 auto cols_val = dataset.
get_numeric<uint16_t>(tags::columns);
153 std::cout << "\nImage dimensions: "
154 << rows_val.value_or(0) << " x " << cols_val.value_or(0) << " pixels\n";
155
157
158
159
160
161
162
163
164
165
166
168
169 std::cout << "DICOM Part 10 file structure:\n";
170 std::cout << " 1. 128-byte preamble (typically zeros)\n";
171 std::cout << " 2. 'DICM' magic number\n";
172 std::cout << " 3. File Meta Information (always Explicit VR Little Endian)\n";
173 std::cout << " 4. Dataset (encoded per Transfer Syntax)\n\n";
174
175
176
177 auto dicom_file = core::dicom_file::create(
178 dataset,
179 enc::transfer_syntax::explicit_vr_little_endian);
180
181 std::cout << "Transfer Syntax: "
182 << dicom_file.transfer_syntax().name() << "\n\n";
183
184
185 const std::string output_path = "hello_dicom_output.dcm";
186 auto save_result = dicom_file.save(output_path);
187
188 if (save_result.is_ok()) {
190 } else {
192 return 1;
193 }
194
195
196
197
198
200
201 auto read_result = core::dicom_file::open(output_path);
202
203 if (read_result.is_ok()) {
204 auto& loaded_file = read_result.value();
205 const auto& loaded_ds = loaded_file.dataset();
206
208
209 std::cout << "\nFile properties:\n";
210 std::cout << " Transfer Syntax: " << loaded_file.transfer_syntax().name() << "\n";
211 std::cout << " SOP Class UID: " << loaded_file.sop_class_uid() << "\n";
212 std::cout << " Element count: " << loaded_ds.size() << "\n\n";
213
214
215 std::cout << "All elements in the dataset:\n";
216 std::cout << std::string(60, '-') << "\n";
217
218 for (const auto& [tag, element] : loaded_ds) {
219 auto value_result = element.as_string();
220 std::string value_str = value_result.is_ok()
221 ? value_result.value()
222 : "<binary data>";
223
224
225 if (value_str.length() > 40) {
226 value_str = value_str.substr(0, 37) + "...";
227 }
228
229 std::cout << tag.to_string() << " "
231 << value_str << "\n";
232 }
233 std::cout << std::string(60, '-') << "\n";
234
235 } else {
237 return 1;
238 }
239
240
241
242
243
245
247 "Congratulations! You have learned:",
248 "",
249 "1. DICOM Tags - (Group, Element) pairs that identify data",
250 "2. Value Representations - Data types like PN, DA, UI, US",
251 "3. DICOM Dataset - Ordered collection of elements",
252 "4. DICOM File - Part 10 format for file storage",
253 "",
254 "Next step: Level 2 - Echo Server (DICOM networking)"
255 });
256
257 std::cout << "\nYou can verify the output file with DCMTK:\n";
258 std::cout << " dcmdump " << output_path << "\n\n";
259
260 return 0;
261}
Represents a DICOM Dataset (ordered collection of Data Elements)
void set_numeric(dicom_tag tag, encoding::vr_type vr, T value)
Set a numeric value for the given tag.
auto size() const noexcept -> size_t
Get the number of elements in the dataset.
auto get_numeric(dicom_tag tag) const -> std::optional< T >
Get the numeric value of an element.
void set_string(dicom_tag tag, encoding::vr_type vr, std::string_view value)
Set a string value for the given tag.
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
Represents a DICOM tag (Group, Element pair)
auto to_string() const -> std::string
Convert to string representation.
constexpr std::string_view to_string(vr_type vr) noexcept
Converts a vr_type to its two-character string representation.
void print_error(std::string_view message)
Print an error message.
void print_table(std::string_view title, const std::vector< std::pair< std::string, std::string > > &rows)
Print a key-value table.
void print_header(std::string_view title)
Print a header/title with decorative border.
void print_success(std::string_view message)
Print a success message.
void print_section(std::string_view title)
Print a section header.
void print_box(const std::vector< std::string > &lines)
Print text in a decorative box.