Skip to content

Commit

Permalink
Add instance frame retrieval
Browse files Browse the repository at this point in the history
  • Loading branch information
feliwir committed Feb 28, 2024
1 parent b2c0039 commit 153fd83
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ derive_more = "0.99.17"
dicom = "0.6.3"
dicom-json = "0.1.1"
dicom-object = "0.6.3"
dicom-pixeldata = { version = "0.2.2", features = ["image"] }
futures-util = "0.3.30"
httparse = "1.8.0"
local-waker = "0.1.4"
Expand Down
1 change: 1 addition & 0 deletions server/src/actix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub fn dicomweb_config(cfg: &mut actix_web::web::ServiceConfig) {
.service(search_instances_series_level)
.service(retrieve_instance)
.service(retrieve_instance_metadata)
.service(retrieve_instance_frames)
.service(retrieve_series)
.service(retrieve_series_metadata)
.service(retrieve_study)
Expand Down
13 changes: 12 additions & 1 deletion server/src/actix/multipart/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl MultipartWriter {
}

pub fn add(self: &mut Self, mut reader: impl Read, headers: &str) -> io::Result<u64> {
// writer for the result
// writer for our buffer
let mut writer = std::io::BufWriter::new(&mut self.data);

// write the boundary
Expand All @@ -47,4 +47,15 @@ impl MultipartWriter {
// write the content
io::copy(&mut reader, &mut writer)
}

pub fn finish(self: &mut Self) {
// writer for our buffer
let mut writer = std::io::BufWriter::new(&mut self.data);

// write the final boundary
writer.write_all(b"\r\n").unwrap();
writer.write_all(b"--").unwrap();
writer.write_all(self.boundary.as_bytes()).unwrap();
writer.write_all(b"--").unwrap();
}
}
54 changes: 53 additions & 1 deletion server/src/actix/wado.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::io::Write;
use std::{io::Write};

use actix_web::{get, web, HttpResponse, Responder};
use dicom::dictionary_std::tags;
use dicom_json::DicomJson;
use dicom_object::InMemDicomObject;
use dicom_pixeldata::PixelDecoder;

use crate::{actix::MultipartWriter, DicomWebServer};

Expand Down Expand Up @@ -33,6 +34,9 @@ pub async fn retrieve_study(
}
}

// Finish the multipart stream
mp.finish();

let content_type = format!(
"multipart/related; type=application/dicom; boundary={}",
mp.boundary
Expand Down Expand Up @@ -94,6 +98,9 @@ pub async fn retrieve_series(
}
}

// Finish the multipart stream
mp.finish();

let content_type = format!(
"multipart/related; type=application/dicom; boundary={}",
mp.boundary
Expand Down Expand Up @@ -154,6 +161,9 @@ pub async fn retrieve_instance(
return HttpResponse::InternalServerError().body(e.to_string());
}

// Finish the multipart stream
mp.finish();

let content_type = format!(
"multipart/related; type=application/dicom; boundary={}",
mp.boundary
Expand Down Expand Up @@ -184,11 +194,53 @@ pub async fn retrieve_instance_metadata(
}
}

#[get("/studies/{study_uid}/series/{series_uid}/instances/{instance_uid}/frames/{frame_list}")]
pub async fn retrieve_instance_frames(
callbacks: web::Data<DicomWebServer>,
path: web::Path<(String, String, String, String)>,
) -> impl Responder {
let (study_uid, series_uid, instance_uid, _frame_list) = path.into_inner();
let result = (callbacks.retrieve_instance)(&study_uid, &series_uid, &instance_uid);

match result {
Ok(dcm_file) => {
// TODO: use the framelist to extract the frames from the pixel data
if let Ok(pixel_data) = dcm_file.decode_pixel_data() {
let mut mp = MultipartWriter::new();
let mut data: Vec<u8> = Vec::new();

// Write the pixel data to memory and add it to our stream
if let Err(e) = data.write_all(&pixel_data.data()) {
return HttpResponse::InternalServerError().body(e.to_string());
}

if let Err(e) = mp.add(&*data, "Content-Type: application/octet-stream") {
return HttpResponse::InternalServerError().body(e.to_string());
}

// Finish the multipart stream
mp.finish();

let content_type = format!(
"multipart/related; type=application/octet-stream; boundary={}",
mp.boundary
);

return HttpResponse::Ok().content_type(content_type).body(mp.data);
} else {
return HttpResponse::InternalServerError().body("No pixel data found");
}
}
Err(e) => return HttpResponse::InternalServerError().body(e.to_string()),
}
}

pub fn wado_config(cfg: &mut web::ServiceConfig) {
cfg.service(retrieve_study)
.service(retrieve_study_metadata)
.service(retrieve_series)
.service(retrieve_series_metadata)
.service(retrieve_instance)
.service(retrieve_instance_frames)
.service(retrieve_instance_metadata);
}

0 comments on commit 153fd83

Please sign in to comment.