openslide/
utils.rs

1//! Misc utility definitions
2
3use std::fmt::{Display, Debug};
4
5use num::{ToPrimitive, Unsigned, Integer};
6use image::{Rgba, RgbaImage};
7use failure::{err_msg, Error};
8
9
10/// A list of supported formats
11///
12/// Information gathered from [https://openslide.org/formats/](https://openslide.org/formats/)
13///
14#[derive(Clone, Debug)]
15pub enum Format {
16    /// Single-file pyramidal tiled TIFF, with non-standard metadata and compression.
17    ///
18    /// File extensions:
19    /// 	.svs, .tif
20    Aperio,
21	/// Multi-file JPEG/NGR with proprietary metadata and index file formats, and single-file
22	/// TIFF-like format with proprietary metadata.
23	///
24	/// File extensions:
25    /// 	.vms, .vmu, .ndpi
26    Hamamatsu,
27    /// Single-file pyramidal tiled BigTIFF with non-standard metadata.
28    ///
29    /// File extensions
30    /// 	.scn
31    Leica,
32    /// Multi-file with very complicated proprietary metadata and indexes.
33    ///
34    /// File extensions
35    /// 	.mrxs
36    Mirax,
37    /// Single-file pyramidal tiled TIFF or BigTIFF with non-standard metadata.
38    ///
39    /// File extensions
40    ///     .tiff
41    Phillips,
42    /// SQLite database containing pyramid tiles and metadata.
43    ///
44    /// File extensions
45    ///     .svslide
46    Sakura,
47    /// Single-file pyramidal tiled TIFF, with non-standard metadata and overlaps. Additional files
48    /// contain more metadata and detailed overlap info.
49    ///
50    /// File extensions
51    ///     .tif
52    Trestle,
53    /// Single-file pyramidal tiled BigTIFF, with non-standard metadata and overlaps.
54    ///
55    /// File extensions
56    ///     .bif, .tif
57    Ventana,
58    /// Single-file pyramidal tiled TIFF.
59    ///
60    /// File extensions
61    ///     .tif
62    GenericTiledTiff,
63}
64
65/// The different ways the u8 color values are encoded into a u32 value.
66///
67/// A successfull reading from OpenSlide's `read_region()` will result in a buffer of `u32` with
68/// `height * width` elements, where `height` and `width` is the shape (in pixels) of the read
69/// region. This `u32` value consist of four `u8` values which are the red, green, blue, and alpha
70/// value of a certain pixel. This enum determines in which order to arange these channels within
71/// one element.
72#[derive(Clone, Debug)]
73pub enum WordRepresentation {
74    /// From most significant bit to least significant bit: `[alpha, red, green, blue]`
75    BigEndian,
76    /// From most significant bit to least significant bit: `[blue, green, red, alpha]`
77    LittleEndian,
78}
79
80/// This function takes a buffer, as the one obtained from openslide::read_region, and decodes into
81/// an Rgba image buffer.
82pub fn decode_buffer<T: Unsigned + Integer + ToPrimitive + Debug + Display + Clone + Copy>(
83    buffer: &Vec<u32>,
84    height: T,
85    width: T,
86    word_representation: WordRepresentation
87) -> Result<RgbaImage, Error> {
88    let (a_pos, r_pos, g_pos, b_pos) = match word_representation {
89        WordRepresentation::BigEndian => (0, 1, 2, 3),
90        WordRepresentation::LittleEndian => (3, 2, 1, 0),
91    };
92
93    let mut rgba_image = RgbaImage::new(
94        width.to_u32().ok_or(err_msg("Conversion to primitive error"))?,
95        height.to_u32().ok_or(err_msg("Conversion to primitive error"))?);
96
97    for (col, row, pixel) in rgba_image.enumerate_pixels_mut() {
98        let curr_pos = row * width.to_u32().ok_or(err_msg("Conversion to primitive error"))? + col;
99        let values = buffer[curr_pos as usize];
100        // TODO: Iterate over chars() instead (?)
101        let bit_repr = format!("{:b}", values);
102        let alpha_bit_repr = String::from(&bit_repr[(8 * a_pos)..(8 * a_pos + 8)]);
103        let red_bit_repr = String::from(&bit_repr[(8 * r_pos)..(8 * r_pos + 8)]);
104        let green_bit_repr = String::from(&bit_repr[(8 * g_pos)..(8 * g_pos + 8)]);
105        let blue_bit_repr = String::from(&bit_repr[(8 * b_pos)..(8 * b_pos + 8)]);
106
107        let alpha = u8::from_str_radix(&alpha_bit_repr, 2)?;
108        let mut red = u8::from_str_radix(&red_bit_repr, 2)?;
109        let mut green = u8::from_str_radix(&green_bit_repr, 2)?;
110        let mut blue = u8::from_str_radix(&blue_bit_repr, 2)?;
111
112
113        if alpha != 0 && alpha != 255 {
114            red = (red as f32 * (255.0 / alpha as f32)).round().max(0.0).min(255.0) as u8;
115            green = (green as f32 * (255.0 / alpha as f32)).round().max(0.0).min(255.0) as u8;
116            blue = (blue as f32 * (255.0 / alpha as f32)).round().max(0.0).min(255.0) as u8;
117        }
118
119        *pixel = Rgba([red, green, blue, alpha]);
120    }
121
122    Ok(rgba_image)
123}