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