I'd raise the question whether you really need to convert the image.
If you need access on the matrix's elements, you can implement an appropriate associated function for an image new type, since a u32 obviously requires less storage than a [[u8; 9]; 3].
So if and when you need to access the respective matrix's fields, you can use a constant and rather cheap™ on the fly operation like so:
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Image(u32);
impl Image {
pub const fn get(&self, outer: u8, inner: u8) -> u8 {
1 & (self.0 >> (outer * 9) + inner) as u8
}
}
Of course you may want to implement some additional guards to limit the indices to valid values.
If you use a library for matrix operations, you can implementsimplement its respective traits for the Image(u32) new type and treat it as a matrix.