1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use libc::{c_uchar, c_uint, size_t};
use std::slice;
use strum_macros::EnumString;
use snafu::{ResultExt, Snafu};

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("GDCM decoding error"))]
    GdcmDecodingError
}

pub type Result<T, E = Error> = std::result::Result<T, E>;

/// PhotometricInterpretation Type for GDCM
#[derive(Debug, PartialEq, EnumString)]
#[allow(non_camel_case_types)]
pub enum GDCMPhotometricInterpretation {
    UNKNOWN = 0,
    MONOCHROME1,
    MONOCHROME2,
    PALETTE_COLOR,
    RGB,
    HSV,
    ARGB, // retired
    CMYK,
    YBR_FULL,
    YBR_FULL_422,
    YBR_PARTIAL_422,
    YBR_PARTIAL_420,
    YBR_ICT,
    YBR_RCT,
    PI_END,
}

pub type InvalidGDCMPI = strum::ParseError;

/// GDCM TransferSyntax encodings for GDCM
#[derive(Debug, PartialEq, EnumString)]
#[allow(non_camel_case_types)]
pub enum GDCMTransferSyntax {
    #[strum(serialize = "1.2.840.10008.1.2")]
    ImplicitVRLittleEndian = 0,
    ImplicitVRBigEndianPrivateGE, // Unknown
    #[strum(serialize = "1.2.840.10008.1.2.1")]
    ExplicitVRLittleEndian,
    #[strum(serialize = "1.2.840.10008.1.2.1.99")]
    DeflatedExplicitVRLittleEndian,
    #[strum(serialize = "1.2.840.10008.1.2.2")]
    ExplicitVRBigEndian,
    #[strum(serialize = "1.2.840.10008.1.2.4.50")]
    JPEGBaselineProcess1,
    #[strum(serialize = "1.2.840.10008.1.2.4.51")]
    JPEGExtendedProcess2_4,
    #[strum(serialize = "1.2.840.10008.1.2.4.52")]
    JPEGExtendedProcess3_5,
    #[strum(serialize = "1.2.840.10008.1.2.4.53")]
    JPEGSpectralSelectionProcess6_8,
    #[strum(serialize = "1.2.840.10008.1.2.4.55")]
    JPEGFullProgressionProcess10_12,
    #[strum(serialize = "1.2.840.10008.1.2.4.57")]
    JPEGLosslessProcess14,
    #[strum(serialize = "1.2.840.10008.1.2.4.70")]
    JPEGLosslessProcess14_1,
    #[strum(serialize = "1.2.840.10008.1.2.4.80")]
    JPEGLSLossless,
    #[strum(serialize = "1.2.840.10008.1.2.4.81")]
    JPEGLSNearLossless,
    #[strum(serialize = "1.2.840.10008.1.2.4.90")]
    JPEG2000Lossless,
    #[strum(serialize = "1.2.840.10008.1.2.4.91")]
    JPEG2000,
    #[strum(serialize = "1.2.840.10008.1.2.4.92")]
    JPEG2000Part2Lossless,
    #[strum(serialize = "1.2.840.10008.1.2.4.93")]
    JPEG2000Part2,
    #[strum(serialize = "1.2.840.10008.1.2.5")]
    RLELossless,
    #[strum(serialize = "1.2.840.10008.1.2.4.100")]
    MPEG2MainProfile,
    ImplicitVRBigEndianACRNEMA, // Unkown
    WeirdPapryus,               // Unknown
    CT_private_ELE,             // Unknown
    #[strum(serialize = "1.2.840.10008.1.2.4.95")]
    JPIPReferenced,
    #[strum(serialize = "1.2.840.10008.1.2.4.101")]
    MPEG2MainProfileHighLevel,
    #[strum(serialize = "1.2.840.10008.1.2.4.102")]
    MPEG4AVCH264HighProfileLevel4_1,
    #[strum(serialize = "1.2.840.10008.1.2.4.103")]
    MPEG4AVCH264BDcompatibleHighProfileLevel4_1,
    TS_END,
}

pub type InvalidGDCMTS = strum::ParseError;

/// Pixel data managed by GDCM
#[repr(C)]
struct pixel_data {
    pixel_data: *const c_uchar,
    status: c_uint,
    size: size_t,
}

extern "C" {
    /// Decodes a single frame buffer in GDCM
    fn c_decode_single_frame_compressed(
        i_buffer_ptr: *const c_uchar,
        i_buffer_len: size_t,
        width: u32,
        height: u32,
        pi_type: u32,
        ts_type: u32,
        samples_per_pixel: u16,
        bits_allocated: u16,
        bits_stored: u16,
        high_bit: u16,
        pixel_representation: u16,
    ) -> pixel_data;
}

/// Decodes a single frame buffer in GDCM
pub fn decode_single_frame_compressed(
    i_buffer: &Vec<u8>,
    width: u32,
    height: u32,
    pi_type: GDCMPhotometricInterpretation,
    ts_type: GDCMTransferSyntax,
    samples_per_pixel: u16,
    bits_allocated: u16,
    bits_stored: u16,
    high_bit: u16,
    pixel_representation: u16,
) -> Result<Box<[u8]>, Error> {
    let ret = unsafe {
        c_decode_single_frame_compressed(
            i_buffer.as_ptr(),
            i_buffer.len(),
            width,
            height,
            pi_type as u32,
            ts_type as u32,
            samples_per_pixel,
            bits_allocated,
            bits_stored,
            high_bit,
            pixel_representation,
        )
    };
    match ret.status {
        0 => unsafe {
            let slice = slice::from_raw_parts_mut(ret.pixel_data as *mut _, ret.size);
            Ok(Box::from_raw(slice))
        },
        _ => GdcmDecodingError.fail()
    }
}