PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
dx_storage.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11
12#include <algorithm>
13#include <array>
14
16
17// =============================================================================
18// Transfer Syntaxes
19// =============================================================================
20
21std::vector<std::string> get_dx_transfer_syntaxes() {
22 return {
23 // Explicit VR Little Endian (preferred for interoperability)
24 "1.2.840.10008.1.2.1",
25 // Implicit VR Little Endian (universal baseline)
26 "1.2.840.10008.1.2",
27 // HTJ2K Lossless (high-throughput lossless for large DX images)
28 "1.2.840.10008.1.2.4.201",
29 // JPEG Lossless (for diagnostic quality - most important for DX)
30 "1.2.840.10008.1.2.4.70",
31 // JPEG 2000 Lossless (better compression, good for large DX images)
32 "1.2.840.10008.1.2.4.90",
33 // JPEG 2000 Lossy (for archival with acceptable quality loss)
34 "1.2.840.10008.1.2.4.91",
35 // RLE Lossless (simple lossless compression)
36 "1.2.840.10008.1.2.5"
37 };
38}
39
40// =============================================================================
41// Photometric Interpretation
42// =============================================================================
43
44std::string_view to_string(dx_photometric_interpretation interp) noexcept {
45 switch (interp) {
47 return "MONOCHROME1";
49 return "MONOCHROME2";
50 }
51 return "MONOCHROME2";
52}
53
55parse_dx_photometric_interpretation(std::string_view value) noexcept {
56 if (value == "MONOCHROME1") {
58 }
59 // Default to MONOCHROME2 for DX
61}
62
63bool is_valid_dx_photometric(std::string_view value) noexcept {
64 return value == "MONOCHROME1" || value == "MONOCHROME2";
65}
66
67// =============================================================================
68// Image Type
69// =============================================================================
70
71std::string_view to_string(dx_image_type type) noexcept {
72 switch (type) {
74 return "FOR PRESENTATION";
76 return "FOR PROCESSING";
77 }
78 return "FOR PRESENTATION";
79}
80
81// =============================================================================
82// View Position
83// =============================================================================
84
85std::string_view to_string(dx_view_position position) noexcept {
86 switch (position) {
88 return "AP";
90 return "PA";
92 return "LATERAL";
94 return "OBLIQUE";
96 return "";
97 }
98 return "";
99}
100
101dx_view_position parse_view_position(std::string_view value) noexcept {
102 if (value == "AP") return dx_view_position::ap;
103 if (value == "PA") return dx_view_position::pa;
104 if (value == "LATERAL" || value == "LAT" ||
105 value == "LL" || value == "RL") {
107 }
108 if (value == "OBLIQUE" || value == "OBL" ||
109 value == "LAO" || value == "RAO" ||
110 value == "LPO" || value == "RPO") {
112 }
114}
115
116// =============================================================================
117// Detector Type
118// =============================================================================
119
120std::string_view to_string(dx_detector_type type) noexcept {
121 switch (type) {
123 return "DIRECT";
125 return "INDIRECT";
127 return "STORAGE";
129 return "FILM";
130 }
131 return "DIRECT";
132}
133
134dx_detector_type parse_detector_type(std::string_view value) noexcept {
135 if (value == "DIRECT") return dx_detector_type::direct;
136 if (value == "INDIRECT") return dx_detector_type::indirect;
137 if (value == "STORAGE") return dx_detector_type::storage;
138 if (value == "FILM") return dx_detector_type::film;
139 // Default to direct for modern DR systems
141}
142
143// =============================================================================
144// Body Part
145// =============================================================================
146
147std::string_view to_string(dx_body_part part) noexcept {
148 switch (part) {
149 case dx_body_part::chest: return "CHEST";
150 case dx_body_part::abdomen: return "ABDOMEN";
151 case dx_body_part::pelvis: return "PELVIS";
152 case dx_body_part::spine: return "SPINE";
153 case dx_body_part::skull: return "SKULL";
154 case dx_body_part::hand: return "HAND";
155 case dx_body_part::foot: return "FOOT";
156 case dx_body_part::knee: return "KNEE";
157 case dx_body_part::elbow: return "ELBOW";
158 case dx_body_part::shoulder: return "SHOULDER";
159 case dx_body_part::hip: return "HIP";
160 case dx_body_part::wrist: return "WRIST";
161 case dx_body_part::ankle: return "ANKLE";
162 case dx_body_part::extremity: return "EXTREMITY";
163 case dx_body_part::breast: return "BREAST";
164 case dx_body_part::other: return "";
165 }
166 return "";
167}
168
169dx_body_part parse_body_part(std::string_view value) noexcept {
170 if (value == "CHEST") return dx_body_part::chest;
171 if (value == "ABDOMEN") return dx_body_part::abdomen;
172 if (value == "PELVIS") return dx_body_part::pelvis;
173 if (value == "SPINE" || value == "CSPINE" || value == "TSPINE" ||
174 value == "LSPINE" || value == "SSPINE") {
175 return dx_body_part::spine;
176 }
177 if (value == "SKULL" || value == "HEAD") return dx_body_part::skull;
178 if (value == "HAND" || value == "FINGER") return dx_body_part::hand;
179 if (value == "FOOT" || value == "TOE") return dx_body_part::foot;
180 if (value == "KNEE") return dx_body_part::knee;
181 if (value == "ELBOW") return dx_body_part::elbow;
182 if (value == "SHOULDER") return dx_body_part::shoulder;
183 if (value == "HIP") return dx_body_part::hip;
184 if (value == "WRIST") return dx_body_part::wrist;
185 if (value == "ANKLE") return dx_body_part::ankle;
186 if (value == "EXTREMITY" || value == "ARM" || value == "LEG") {
188 }
189 if (value == "BREAST") return dx_body_part::breast;
190 return dx_body_part::other;
191}
192
193// =============================================================================
194// SOP Class Information
195// =============================================================================
196
197namespace {
198
199// Static array of DX SOP class information
200constexpr std::array<dx_sop_class_info, 6> dx_sop_classes = {{
201 {
203 "Digital X-Ray Image Storage - For Presentation",
204 "Processed digital radiography images ready for clinical review",
206 false,
207 false
208 },
209 {
211 "Digital X-Ray Image Storage - For Processing",
212 "Raw digital radiography data requiring further processing",
214 false,
215 false
216 },
217 {
219 "Digital Mammography X-Ray Image Storage - For Presentation",
220 "Processed digital mammography images ready for clinical review",
222 true,
223 false
224 },
225 {
227 "Digital Mammography X-Ray Image Storage - For Processing",
228 "Raw digital mammography data requiring further processing",
230 true,
231 false
232 },
233 {
235 "Digital Intra-Oral X-Ray Image Storage - For Presentation",
236 "Processed dental intra-oral images ready for clinical review",
238 false,
239 true
240 },
241 {
243 "Digital Intra-Oral X-Ray Image Storage - For Processing",
244 "Raw dental intra-oral data requiring further processing",
246 false,
247 true
248 }
249}};
250
251} // namespace
252
253std::vector<std::string> get_dx_storage_sop_classes(bool include_mammography,
254 bool include_intraoral) {
255 std::vector<std::string> result;
256 result.reserve(6);
257
258 for (const auto& info : dx_sop_classes) {
259 // Always include general DX
260 if (!info.is_mammography && !info.is_intraoral) {
261 result.emplace_back(info.uid);
262 }
263 // Include mammography if requested
264 else if (info.is_mammography && include_mammography) {
265 result.emplace_back(info.uid);
266 }
267 // Include intra-oral if requested
268 else if (info.is_intraoral && include_intraoral) {
269 result.emplace_back(info.uid);
270 }
271 }
272
273 return result;
274}
275
276const dx_sop_class_info*
277get_dx_sop_class_info(std::string_view uid) noexcept {
278 auto it = std::find_if(
279 dx_sop_classes.begin(),
280 dx_sop_classes.end(),
281 [uid](const auto& info) { return info.uid == uid; }
282 );
283
284 if (it != dx_sop_classes.end()) {
285 return &(*it);
286 }
287 return nullptr;
288}
289
290bool is_dx_storage_sop_class(std::string_view uid) noexcept {
291 return get_dx_sop_class_info(uid) != nullptr;
292}
293
294bool is_dx_for_processing_sop_class(std::string_view uid) noexcept {
295 const auto* info = get_dx_sop_class_info(uid);
296 return info != nullptr && info->image_type == dx_image_type::for_processing;
297}
298
299bool is_dx_for_presentation_sop_class(std::string_view uid) noexcept {
300 const auto* info = get_dx_sop_class_info(uid);
301 return info != nullptr && info->image_type == dx_image_type::for_presentation;
302}
303
304bool is_mammography_sop_class(std::string_view uid) noexcept {
305 const auto* info = get_dx_sop_class_info(uid);
306 return info != nullptr && info->is_mammography;
307}
308
309} // namespace kcenon::pacs::services::sop_classes
Digital X-Ray (DX) Image Storage SOP Classes.
constexpr std::string_view dx_image_storage_for_processing_uid
Digital X-Ray Image Storage - For Processing SOP Class UID Used for raw detector data requiring addit...
Definition dx_storage.h:49
dx_detector_type
DX detector technology types.
Definition dx_storage.h:192
@ indirect
Indirect conversion (scintillator + photodiode)
std::vector< std::string > get_dx_transfer_syntaxes()
Get recommended transfer syntaxes for DX images.
bool is_dx_for_processing_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a For Processing SOP Class.
dx_photometric_interpretation
Supported photometric interpretations for DX images.
Definition dx_storage.h:105
dx_photometric_interpretation parse_dx_photometric_interpretation(std::string_view value) noexcept
Parse DICOM photometric interpretation string for DX.
std::vector< std::string > get_dx_storage_sop_classes(bool include_mammography=true, bool include_intraoral=true)
Get all DX Storage SOP Class UIDs.
constexpr std::string_view dx_image_storage_for_presentation_uid
Digital X-Ray Image Storage - For Presentation SOP Class UID Used for images ready for display and cl...
Definition dx_storage.h:44
dx_view_position
Common radiographic view positions for DX images.
Definition dx_storage.h:161
constexpr std::string_view intraoral_image_storage_for_processing_uid
Digital Intra-Oral X-Ray Image Storage - For Processing.
Definition dx_storage.h:75
constexpr std::string_view mammography_image_storage_for_processing_uid
Digital Mammography X-Ray Image Storage - For Processing.
Definition dx_storage.h:62
bool is_dx_for_presentation_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a For Presentation SOP Class.
dx_detector_type parse_detector_type(std::string_view value) noexcept
Parse DICOM detector type string.
constexpr std::string_view intraoral_image_storage_for_presentation_uid
Digital Intra-Oral X-Ray Image Storage - For Presentation.
Definition dx_storage.h:71
bool is_valid_dx_photometric(std::string_view value) noexcept
Check if photometric interpretation is valid for DX.
bool is_dx_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a DX Storage SOP Class.
const dx_sop_class_info * get_dx_sop_class_info(std::string_view uid) noexcept
Get information about a specific DX SOP Class.
dx_image_type
DX image purpose classification.
Definition dx_storage.h:139
@ for_presentation
Ready for display and diagnosis.
@ for_processing
Raw data requiring further processing.
dx_body_part
Common body parts for DX imaging.
Definition dx_storage.h:300
dx_view_position parse_view_position(std::string_view value) noexcept
Parse DICOM view position string.
bool is_mammography_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a mammography SOP Class.
constexpr std::string_view mammography_image_storage_for_presentation_uid
Digital Mammography X-Ray Image Storage - For Presentation.
Definition dx_storage.h:58
std::string_view to_string(dx_photometric_interpretation interp) noexcept
Convert photometric interpretation enum to DICOM string.
dx_body_part parse_body_part(std::string_view value) noexcept
Parse DICOM body part examined string.
std::string_view uid