-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A library to help to read, manipulate and save ciod files #553
Comments
Thank you for sharing!
That idea is aligned with the plans for an IOD/module API for the most part, so it is already on the roadmap and would indeed be great that it be part of the DICOM-rs ecosystem. I would be grateful with that contribution to the project, and I would provide the maintenance and synergy that the project has in place for all covered crates. We can go into further detail about the feature set here or on Zulip.
Part 3 is where one would find all the definitions (XML version here). Some details might only be written in prose or provided in other parts of the standard, but we already have a data element dictionary that can be depended on for code generation. There is also an example of parsing the UID table from PS3.6 in |
Is there an api in mind for this IOD api? I might want to work on making this exist if there's an idea of what it would look like |
Primarily, I would envision IOD (or Module)-like structs offering methods to 1) read from different sources (file, raw bytes, in-mem DICOM object) into a value of type fn open_file(path: impl AsRef<Path>) -> Result<Self>;
fn read_data(path: impl std::io::Read) -> Result<Self>;
fn from_obj(dicom_object: &InMemDicomObject) -> Result<Self>; Whether this would require implementing more traits to facilitate the process of generating the implementation is an implementation detail. A good choice of methods may also allow us to provide default implementations (e.g. Here's an idea of how it would work to the API user. use dicom_iod::Module; // import trait & derive macro
#[derive(Module)]
struct PatientModule {
#[iod(...)] // <-- whichever parameters required here
patient_name: String,
#[iod(...)]
patient_id: Option<String>,
#[iod(...)]
patient_birthdate: Option<String>,
// etc
}
// read enough DICOM data from a file to populate a `PatientModule`
let mut data = PatientModule::open_file("0001.dcm")?;
println!("{} (ID: {})", data.patient_name, data.patient_id);
// e.g. remove birth date
data.patient_birthdate = None;
// encode to byte vector
let mut buf = Vec::<u8>::new();
let ts = dicom_transfer_syntax_registry::entries::EXPLICIT_VR_LITTLE_ENDIAN.erased();
data.write_dataset_with_ts(&mut buf, &ts)?; So a baseline implementation of a potential
|
Currently, we have implemented CIOD classes and all the required modules for them(without most of the optional ones):
We are currently still tweaking a few things so we should be releasing the first test version soon. As time goes by it looks like full automatic generation of new ciods/modules is less and less likely due to quite specific validation rules |
Right, we might end up with a hybrid approach, where the baseline is generated from the standard but the modules committed to the crate are adjusted by hand to cover the necessary validation rules. It would also be nice if we could feature-gate the IODs that the developer might need, so that the unused ones do not have to be compiled. This might make a greater difference as the list of classes expands. |
Hey @qarmin I had some time this weekend to play around with some ideas I had for this and was wondering where you're at for this.
We can certainly build on top of this for more convenience functions, but writing modules feels to me like it would be a good fit for a serde api, and would likely be a good intermediate step before writing a full module api. |
Recently in company we needed to create a tool that could:
So we created for internal use a library that makes it much easier to manage this.
The code looks similar to this(there are defined attributes i.e. CS, UI etc. and separate modules in a separate file):
Specific modules are implemented in similar structure:
objects can be created by loading a file from memory like
OphtalmicVisualFieldStaticPerimetryMeasurements::load(&file_path)
or manually by creating them within rust:So my questions:
The text was updated successfully, but these errors were encountered: