1use crate::protocol::message::Message;
68use crate::error::{IgtlError, Result};
69use bytes::{Buf, BufMut};
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum ImageScalarType {
74 Int8 = 2,
75 Uint8 = 3,
76 Int16 = 4,
77 Uint16 = 5,
78 Int32 = 6,
79 Uint32 = 7,
80 Float32 = 10,
81 Float64 = 11,
82}
83
84impl ImageScalarType {
85 pub fn size(&self) -> usize {
87 match self {
88 ImageScalarType::Int8 | ImageScalarType::Uint8 => 1,
89 ImageScalarType::Int16 | ImageScalarType::Uint16 => 2,
90 ImageScalarType::Int32 | ImageScalarType::Uint32 | ImageScalarType::Float32 => 4,
91 ImageScalarType::Float64 => 8,
92 }
93 }
94
95 pub fn from_u8(value: u8) -> Result<Self> {
97 match value {
98 2 => Ok(ImageScalarType::Int8),
99 3 => Ok(ImageScalarType::Uint8),
100 4 => Ok(ImageScalarType::Int16),
101 5 => Ok(ImageScalarType::Uint16),
102 6 => Ok(ImageScalarType::Int32),
103 7 => Ok(ImageScalarType::Uint32),
104 10 => Ok(ImageScalarType::Float32),
105 11 => Ok(ImageScalarType::Float64),
106 _ => Err(IgtlError::InvalidSize {
107 expected: 0,
108 actual: value as usize,
109 }),
110 }
111 }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub enum Endian {
117 Big = 1,
118 Little = 2,
119}
120
121impl Endian {
122 pub fn from_u8(value: u8) -> Result<Self> {
124 match value {
125 1 => Ok(Endian::Big),
126 2 => Ok(Endian::Little),
127 _ => Err(IgtlError::InvalidSize {
128 expected: 1,
129 actual: value as usize,
130 }),
131 }
132 }
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub enum CoordinateSystem {
138 RAS = 1, LPS = 2, }
141
142impl CoordinateSystem {
143 pub fn from_u8(value: u8) -> Result<Self> {
145 match value {
146 1 => Ok(CoordinateSystem::RAS),
147 2 => Ok(CoordinateSystem::LPS),
148 _ => Err(IgtlError::InvalidSize {
149 expected: 1,
150 actual: value as usize,
151 }),
152 }
153 }
154}
155
156#[derive(Debug, Clone, PartialEq)]
164pub struct ImageMessage {
165 pub version: u16,
167 pub num_components: u8,
169 pub scalar_type: ImageScalarType,
171 pub endian: Endian,
173 pub coordinate: CoordinateSystem,
175 pub size: [u16; 3],
177 pub matrix: [[f32; 4]; 3],
179 pub data: Vec<u8>,
181}
182
183impl ImageMessage {
184 pub fn new(
186 scalar_type: ImageScalarType,
187 size: [u16; 3],
188 data: Vec<u8>,
189 ) -> Result<Self> {
190 let num_components = 1;
191 let expected_size = (size[0] as usize) * (size[1] as usize) * (size[2] as usize)
192 * (num_components as usize) * scalar_type.size();
193
194 if data.len() != expected_size {
195 return Err(IgtlError::InvalidSize {
196 expected: expected_size,
197 actual: data.len(),
198 });
199 }
200
201 Ok(ImageMessage {
202 version: 1,
203 num_components,
204 scalar_type,
205 endian: Endian::Big,
206 coordinate: CoordinateSystem::RAS,
207 size,
208 matrix: [
209 [1.0, 0.0, 0.0, 0.0],
210 [0.0, 1.0, 0.0, 0.0],
211 [0.0, 0.0, 1.0, 0.0],
212 ],
213 data,
214 })
215 }
216
217 pub fn rgb(
219 scalar_type: ImageScalarType,
220 size: [u16; 3],
221 data: Vec<u8>,
222 ) -> Result<Self> {
223 let num_components = 3;
224 let expected_size = (size[0] as usize) * (size[1] as usize) * (size[2] as usize)
225 * (num_components as usize) * scalar_type.size();
226
227 if data.len() != expected_size {
228 return Err(IgtlError::InvalidSize {
229 expected: expected_size,
230 actual: data.len(),
231 });
232 }
233
234 Ok(ImageMessage {
235 version: 1,
236 num_components,
237 scalar_type,
238 endian: Endian::Big,
239 coordinate: CoordinateSystem::RAS,
240 size,
241 matrix: [
242 [1.0, 0.0, 0.0, 0.0],
243 [0.0, 1.0, 0.0, 0.0],
244 [0.0, 0.0, 1.0, 0.0],
245 ],
246 data,
247 })
248 }
249
250 pub fn with_matrix(mut self, matrix: [[f32; 4]; 3]) -> Self {
252 self.matrix = matrix;
253 self
254 }
255
256 pub fn with_coordinate(mut self, coordinate: CoordinateSystem) -> Self {
258 self.coordinate = coordinate;
259 self
260 }
261
262 pub fn num_pixels(&self) -> usize {
264 (self.size[0] as usize) * (self.size[1] as usize) * (self.size[2] as usize)
265 }
266}
267
268impl Message for ImageMessage {
269 fn message_type() -> &'static str {
270 "IMAGE"
271 }
272
273 fn encode_content(&self) -> Result<Vec<u8>> {
274 let mut buf = Vec::with_capacity(60 + self.data.len());
275
276 buf.put_u16(self.version);
278
279 buf.put_u8(self.num_components);
281
282 buf.put_u8(self.scalar_type as u8);
284
285 buf.put_u8(self.endian as u8);
287
288 buf.put_u8(self.coordinate as u8);
290
291 for &s in &self.size {
293 buf.put_u16(s);
294 }
295
296 for row in &self.matrix {
298 for &val in row {
299 buf.put_f32(val);
300 }
301 }
302
303 buf.extend_from_slice(&self.data);
305
306 Ok(buf)
307 }
308
309 fn decode_content(mut data: &[u8]) -> Result<Self> {
310 if data.len() < 60 {
311 return Err(IgtlError::InvalidSize {
312 expected: 60,
313 actual: data.len(),
314 });
315 }
316
317 let version = data.get_u16();
319
320 let num_components = data.get_u8();
322
323 let scalar_type = ImageScalarType::from_u8(data.get_u8())?;
325
326 let endian = Endian::from_u8(data.get_u8())?;
328
329 let coordinate = CoordinateSystem::from_u8(data.get_u8())?;
331
332 let size = [data.get_u16(), data.get_u16(), data.get_u16()];
334
335 let mut matrix = [[0.0f32; 4]; 3];
337 for row in &mut matrix {
338 for val in row {
339 *val = data.get_f32();
340 }
341 }
342
343 let image_data = data.to_vec();
345
346 let expected_size = (size[0] as usize) * (size[1] as usize) * (size[2] as usize)
348 * (num_components as usize) * scalar_type.size();
349
350 if image_data.len() != expected_size {
351 return Err(IgtlError::InvalidSize {
352 expected: expected_size,
353 actual: image_data.len(),
354 });
355 }
356
357 Ok(ImageMessage {
358 version,
359 num_components,
360 scalar_type,
361 endian,
362 coordinate,
363 size,
364 matrix,
365 data: image_data,
366 })
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use super::*;
373
374 #[test]
375 fn test_message_type() {
376 assert_eq!(ImageMessage::message_type(), "IMAGE");
377 }
378
379 #[test]
380 fn test_scalar_type_size() {
381 assert_eq!(ImageScalarType::Uint8.size(), 1);
382 assert_eq!(ImageScalarType::Uint16.size(), 2);
383 assert_eq!(ImageScalarType::Float32.size(), 4);
384 assert_eq!(ImageScalarType::Float64.size(), 8);
385 }
386
387 #[test]
388 fn test_new_2d() {
389 let size = [256, 256, 1];
390 let data_size = 256 * 256 * 1;
391 let data = vec![0u8; data_size];
392
393 let img = ImageMessage::new(ImageScalarType::Uint8, size, data).unwrap();
394 assert_eq!(img.size, size);
395 assert_eq!(img.num_components, 1);
396 }
397
398 #[test]
399 fn test_new_3d() {
400 let size = [128, 128, 64];
401 let data_size = 128 * 128 * 64;
402 let data = vec![0u8; data_size];
403
404 let img = ImageMessage::new(ImageScalarType::Uint8, size, data).unwrap();
405 assert_eq!(img.size, size);
406 assert_eq!(img.num_pixels(), 128 * 128 * 64);
407 }
408
409 #[test]
410 fn test_rgb() {
411 let size = [100, 100, 1];
412 let data_size = 100 * 100 * 3; let data = vec![0u8; data_size];
414
415 let img = ImageMessage::rgb(ImageScalarType::Uint8, size, data).unwrap();
416 assert_eq!(img.num_components, 3);
417 }
418
419 #[test]
420 fn test_invalid_data_size() {
421 let size = [10, 10, 1];
422 let data = vec![0u8; 50]; let result = ImageMessage::new(ImageScalarType::Uint8, size, data);
425 assert!(result.is_err());
426 }
427
428 #[test]
429 fn test_with_matrix() {
430 let size = [10, 10, 1];
431 let data = vec![0u8; 100];
432 let matrix = [
433 [2.0, 0.0, 0.0, 10.0],
434 [0.0, 2.0, 0.0, 20.0],
435 [0.0, 0.0, 1.0, 0.0],
436 ];
437
438 let img = ImageMessage::new(ImageScalarType::Uint8, size, data)
439 .unwrap()
440 .with_matrix(matrix);
441
442 assert_eq!(img.matrix[0][3], 10.0);
443 assert_eq!(img.matrix[1][3], 20.0);
444 }
445
446 #[test]
447 fn test_encode_decode_small() {
448 let size = [4, 4, 1];
449 let data = vec![128u8; 16];
450
451 let original = ImageMessage::new(ImageScalarType::Uint8, size, data).unwrap();
452 let encoded = original.encode_content().unwrap();
453 let decoded = ImageMessage::decode_content(&encoded).unwrap();
454
455 assert_eq!(decoded.version, original.version);
456 assert_eq!(decoded.num_components, original.num_components);
457 assert_eq!(decoded.scalar_type, original.scalar_type);
458 assert_eq!(decoded.size, original.size);
459 assert_eq!(decoded.data, original.data);
460 }
461
462 #[test]
463 fn test_roundtrip_uint16() {
464 let size = [8, 8, 2];
465 let data_size = 8 * 8 * 2 * 2; let data = vec![0u8; data_size];
467
468 let original = ImageMessage::new(ImageScalarType::Uint16, size, data).unwrap();
469 let encoded = original.encode_content().unwrap();
470 let decoded = ImageMessage::decode_content(&encoded).unwrap();
471
472 assert_eq!(decoded.scalar_type, ImageScalarType::Uint16);
473 assert_eq!(decoded.size, size);
474 assert_eq!(decoded.data.len(), data_size);
475 }
476
477 #[test]
478 fn test_roundtrip_with_matrix() {
479 let size = [5, 5, 1];
480 let data = vec![255u8; 25];
481 let matrix = [
482 [1.0, 0.0, 0.0, 5.0],
483 [0.0, 1.0, 0.0, 10.0],
484 [0.0, 0.0, 1.0, 15.0],
485 ];
486
487 let original = ImageMessage::new(ImageScalarType::Uint8, size, data)
488 .unwrap()
489 .with_matrix(matrix)
490 .with_coordinate(CoordinateSystem::LPS);
491
492 let encoded = original.encode_content().unwrap();
493 let decoded = ImageMessage::decode_content(&encoded).unwrap();
494
495 assert_eq!(decoded.coordinate, CoordinateSystem::LPS);
496 assert_eq!(decoded.matrix, matrix);
497 }
498
499 #[test]
500 fn test_decode_invalid_header() {
501 let data = vec![0u8; 50]; let result = ImageMessage::decode_content(&data);
503 assert!(result.is_err());
504 }
505}