use std::{
fs::File,
io::{BufReader, ErrorKind, Read, Seek, SeekFrom},
path::Path,
};
use dicom::object::{self as dicom_object, DefaultDicomObject};
use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum Error {
#[snafu(display("Could not read Dicom object: {}", source))]
Io { source: std::io::Error },
#[snafu(display("Could not read Dicom preamble"))]
Preamble,
#[snafu(display("Could not parse Dicom object: {}", source))]
Dcm { source: dicom_object::ReadError },
#[snafu(display("Could not parse Dicom object (no preamble?): {}", source))]
DcmNoPreamble { source: dicom_object::ReadError },
}
pub fn read_dcm_file<P: AsRef<Path>>(path: P) -> Result<DefaultDicomObject, Error> {
let path = path.as_ref();
let input = BufReader::new(File::open(path).context(IoSnafu)?);
read_dcm_stream(input)
}
pub fn read_dcm_stream<F: Seek + Read>(mut input: F) -> Result<DefaultDicomObject, Error> {
let mut buf = [0u8; 128 + 4];
match input.read_exact(&mut buf) {
Ok(_) => {
if buf[128..132] == *b"DICM" {
input.seek(SeekFrom::Current(-4)).context(IoSnafu)?;
return read_dcm_stream_without_pixel_data(input).context(DcmSnafu);
}
}
Err(e) => {
if e.kind() != ErrorKind::UnexpectedEof {
return Err(Error::Io { source: e });
}
}
}
input.seek(SeekFrom::Start(0)).context(IoSnafu)?;
read_dcm_stream_without_pixel_data(input).context(DcmNoPreambleSnafu)
}
fn read_dcm_stream_without_pixel_data<F: Read>(
input: F,
) -> Result<DefaultDicomObject, dicom_object::ReadError> {
dicom_object::OpenFileOptions::new()
.read_until(dicom::dictionary_std::tags::PIXEL_DATA)
.read_preamble(dicom_object::file::ReadPreamble::Never)
.from_reader(input)
}