1use crate::error::{IgtlError, Result};
68use crate::protocol::message::Message;
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(scalar_type: ImageScalarType, size: [u16; 3], data: Vec<u8>) -> Result<Self> {
186 let num_components = 1;
187 let expected_size = (size[0] as usize)
188 * (size[1] as usize)
189 * (size[2] as usize)
190 * (num_components as usize)
191 * scalar_type.size();
192
193 if data.len() != expected_size {
194 return Err(IgtlError::InvalidSize {
195 expected: expected_size,
196 actual: data.len(),
197 });
198 }
199
200 Ok(ImageMessage {
201 version: 1,
202 num_components,
203 scalar_type,
204 endian: Endian::Big,
205 coordinate: CoordinateSystem::RAS,
206 size,
207 matrix: [
208 [1.0, 0.0, 0.0, 0.0],
209 [0.0, 1.0, 0.0, 0.0],
210 [0.0, 0.0, 1.0, 0.0],
211 ],
212 data,
213 })
214 }
215
216 pub fn rgb(scalar_type: ImageScalarType, size: [u16; 3], data: Vec<u8>) -> Result<Self> {
218 let num_components = 3;
219 let expected_size = (size[0] as usize)
220 * (size[1] as usize)
221 * (size[2] as usize)
222 * (num_components as usize)
223 * scalar_type.size();
224
225 if data.len() != expected_size {
226 return Err(IgtlError::InvalidSize {
227 expected: expected_size,
228 actual: data.len(),
229 });
230 }
231
232 Ok(ImageMessage {
233 version: 1,
234 num_components,
235 scalar_type,
236 endian: Endian::Big,
237 coordinate: CoordinateSystem::RAS,
238 size,
239 matrix: [
240 [1.0, 0.0, 0.0, 0.0],
241 [0.0, 1.0, 0.0, 0.0],
242 [0.0, 0.0, 1.0, 0.0],
243 ],
244 data,
245 })
246 }
247
248 pub fn with_matrix(mut self, matrix: [[f32; 4]; 3]) -> Self {
250 self.matrix = matrix;
251 self
252 }
253
254 pub fn with_coordinate(mut self, coordinate: CoordinateSystem) -> Self {
256 self.coordinate = coordinate;
257 self
258 }
259
260 pub fn num_pixels(&self) -> usize {
262 (self.size[0] as usize) * (self.size[1] as usize) * (self.size[2] as usize)
263 }
264}
265
266impl Message for ImageMessage {
267 fn message_type() -> &'static str {
268 "IMAGE"
269 }
270
271 fn encode_content(&self) -> Result<Vec<u8>> {
272 let mut buf = Vec::with_capacity(60 + self.data.len());
273
274 buf.put_u16(self.version);
276
277 buf.put_u8(self.num_components);
279
280 buf.put_u8(self.scalar_type as u8);
282
283 buf.put_u8(self.endian as u8);
285
286 buf.put_u8(self.coordinate as u8);
288
289 for &s in &self.size {
291 buf.put_u16(s);
292 }
293
294 for row in &self.matrix {
296 for &val in row {
297 buf.put_f32(val);
298 }
299 }
300
301 buf.extend_from_slice(&self.data);
303
304 Ok(buf)
305 }
306
307 fn decode_content(mut data: &[u8]) -> Result<Self> {
308 if data.len() < 60 {
309 return Err(IgtlError::InvalidSize {
310 expected: 60,
311 actual: data.len(),
312 });
313 }
314
315 let version = data.get_u16();
317
318 let num_components = data.get_u8();
320
321 let scalar_type = ImageScalarType::from_u8(data.get_u8())?;
323
324 let endian = Endian::from_u8(data.get_u8())?;
326
327 let coordinate = CoordinateSystem::from_u8(data.get_u8())?;
329
330 let size = [data.get_u16(), data.get_u16(), data.get_u16()];
332
333 let mut matrix = [[0.0f32; 4]; 3];
335 for row in &mut matrix {
336 for val in row {
337 *val = data.get_f32();
338 }
339 }
340
341 let image_data = data.to_vec();
343
344 let expected_size = (size[0] as usize)
346 * (size[1] as usize)
347 * (size[2] as usize)
348 * (num_components as usize)
349 * scalar_type.size();
350
351 if image_data.len() != expected_size {
352 return Err(IgtlError::InvalidSize {
353 expected: expected_size,
354 actual: image_data.len(),
355 });
356 }
357
358 Ok(ImageMessage {
359 version,
360 num_components,
361 scalar_type,
362 endian,
363 coordinate,
364 size,
365 matrix,
366 data: image_data,
367 })
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374
375 #[test]
376 fn test_message_type() {
377 assert_eq!(ImageMessage::message_type(), "IMAGE");
378 }
379
380 #[test]
381 fn test_scalar_type_size() {
382 assert_eq!(ImageScalarType::Uint8.size(), 1);
383 assert_eq!(ImageScalarType::Uint16.size(), 2);
384 assert_eq!(ImageScalarType::Float32.size(), 4);
385 assert_eq!(ImageScalarType::Float64.size(), 8);
386 }
387
388 #[test]
389 fn test_new_2d() {
390 let size = [256, 256, 1];
391 let data_size = 256 * 256;
392 let data = vec![0u8; data_size];
393
394 let img = ImageMessage::new(ImageScalarType::Uint8, size, data).unwrap();
395 assert_eq!(img.size, size);
396 assert_eq!(img.num_components, 1);
397 }
398
399 #[test]
400 fn test_new_3d() {
401 let size = [128, 128, 64];
402 let data_size = 128 * 128 * 64;
403 let data = vec![0u8; data_size];
404
405 let img = ImageMessage::new(ImageScalarType::Uint8, size, data).unwrap();
406 assert_eq!(img.size, size);
407 assert_eq!(img.num_pixels(), 128 * 128 * 64);
408 }
409
410 #[test]
411 fn test_rgb() {
412 let size = [100, 100, 1];
413 let data_size = 100 * 100 * 3; let data = vec![0u8; data_size];
415
416 let img = ImageMessage::rgb(ImageScalarType::Uint8, size, data).unwrap();
417 assert_eq!(img.num_components, 3);
418 }
419
420 #[test]
421 fn test_invalid_data_size() {
422 let size = [10, 10, 1];
423 let data = vec![0u8; 50]; let result = ImageMessage::new(ImageScalarType::Uint8, size, data);
426 assert!(result.is_err());
427 }
428
429 #[test]
430 fn test_with_matrix() {
431 let size = [10, 10, 1];
432 let data = vec![0u8; 100];
433 let matrix = [
434 [2.0, 0.0, 0.0, 10.0],
435 [0.0, 2.0, 0.0, 20.0],
436 [0.0, 0.0, 1.0, 0.0],
437 ];
438
439 let img = ImageMessage::new(ImageScalarType::Uint8, size, data)
440 .unwrap()
441 .with_matrix(matrix);
442
443 assert_eq!(img.matrix[0][3], 10.0);
444 assert_eq!(img.matrix[1][3], 20.0);
445 }
446
447 #[test]
448 fn test_encode_decode_small() {
449 let size = [4, 4, 1];
450 let data = vec![128u8; 16];
451
452 let original = ImageMessage::new(ImageScalarType::Uint8, size, data).unwrap();
453 let encoded = original.encode_content().unwrap();
454 let decoded = ImageMessage::decode_content(&encoded).unwrap();
455
456 assert_eq!(decoded.version, original.version);
457 assert_eq!(decoded.num_components, original.num_components);
458 assert_eq!(decoded.scalar_type, original.scalar_type);
459 assert_eq!(decoded.size, original.size);
460 assert_eq!(decoded.data, original.data);
461 }
462
463 #[test]
464 fn test_roundtrip_uint16() {
465 let size = [8, 8, 2];
466 let data_size = 8 * 8 * 2 * 2; let data = vec![0u8; data_size];
468
469 let original = ImageMessage::new(ImageScalarType::Uint16, size, data).unwrap();
470 let encoded = original.encode_content().unwrap();
471 let decoded = ImageMessage::decode_content(&encoded).unwrap();
472
473 assert_eq!(decoded.scalar_type, ImageScalarType::Uint16);
474 assert_eq!(decoded.size, size);
475 assert_eq!(decoded.data.len(), data_size);
476 }
477
478 #[test]
479 fn test_roundtrip_with_matrix() {
480 let size = [5, 5, 1];
481 let data = vec![255u8; 25];
482 let matrix = [
483 [1.0, 0.0, 0.0, 5.0],
484 [0.0, 1.0, 0.0, 10.0],
485 [0.0, 0.0, 1.0, 15.0],
486 ];
487
488 let original = ImageMessage::new(ImageScalarType::Uint8, size, data)
489 .unwrap()
490 .with_matrix(matrix)
491 .with_coordinate(CoordinateSystem::LPS);
492
493 let encoded = original.encode_content().unwrap();
494 let decoded = ImageMessage::decode_content(&encoded).unwrap();
495
496 assert_eq!(decoded.coordinate, CoordinateSystem::LPS);
497 assert_eq!(decoded.matrix, matrix);
498 }
499
500 #[test]
501 fn test_decode_invalid_header() {
502 let data = vec![0u8; 50]; let result = ImageMessage::decode_content(&data);
504 assert!(result.is_err());
505 }
506}