Reputation: 53
I work at a project written in Rust that basically mocks a printer. I get printer input, and try to convert it to human readable data (strings, images). So, for reproducing the QR code, I am converting the printer input to BitMap Slices (I created a struct that implements GenericImageView
).
BitmapImageSlice {
height,
width,
buffer: data
}
impl GenericImageView for BitmapImageSlice {
type Pixel = Rgb<u8>;
type InnerImageView = BitmapImageSlice;
fn dimensions(&self) -> (u32, u32) {
(self.width as u32, self.height as u32)
}
fn bounds(&self) -> (u32, u32, u32, u32) {
( 0, 0, self.width as u32, self.height as u32)
}
fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
let byte = self.buffer[x as usize];
let bit_position = 7-y;
let bit = 1 << bit_position;
if (byte & bit as u8) > 0{
Rgb([0, 0, 0])
}
else {
Rgb([255, 255, 255])
}
}
fn inner(&self) -> &Self::InnerImageView {
self
}
}
My question is, how can I convert BitMapImageSlice
values to an image encoded in PNG?
Upvotes: 2
Views: 1019
Reputation: 29983
There is a key problem when trying to make your own implementation of a generic image through the image
crate: there is no support for a 1 bit per pixel color type, and even with an adaptation layer, it will not be compatible with the APIs available.
write_to
only exists for DynamicImage
, which is defined as an enum of built-in implementations. It cannot be extended to consider orphan implementations.save_buffer_with_format
(as proposed here) expects a buffer of pixel samples in accordance to a supported color type.ImageEncoder
for writing encoded content also expects a buffer of pixels following a supported color type.As such, it is more straightforward here to use a supported image type. Convert the bitmap to the L8
color type and use the existing functions from there.
impl BitmapImageSlice {
pub fn to_image(&self) -> ImageBuffer<Luma<u8>, Vec<u8>> {
// NOTE: this depends on the BitmapImageSlice data layout,
// adjust vector construction accordingly
let data: Vec<u8> = self.buffer.iter()
.flat_map(|b| [
b >> 7,
(b >> 6) & 1,
(b >> 5) & 1,
(b >> 4) & 1,
(b >> 3) & 1,
(b >> 2) & 1,
(b >> 1) & 1,
b & 1,
])
.map(|p| p * 0xFF)
.collect();
ImageBuffer::from_vec(self.width, self.height, data).unwrap()
}
}
fn save(bitmap: &BitmapImageSlice) -> image::error::ImageResult<()> {
let img = bitmap.to_image();
image::save_buffer_with_format(
"out.png",
img.as_raw(),
bitmap.width,
bitmap.height,
ColorType::L8,
ImageFormat::Png,
)?;
Ok(())
}
Upvotes: 3