我正在从事一个用 Rust 编写的项目,该项目基本上模拟了打印机。我获取打印机输入,并尝试将其转换为人类可读的数据(字符串、图像)。因此,为了重现 QR 码,我将打印机输入转换为位图切片(我创建了一个实现 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
}
}
我的问题是,如何将 BitMapImageSlice
值转换为以 PNG 编码的图像?
最佳答案
尝试通过 image
箱自行实现通用图像时存在一个关键问题:不支持每像素 1 位的颜色类型 ,即使有适配层,它也不会与可用的 API 兼容。
- 方法
write_to
仅适用于DynamicImage
,它被定义为内置实现的枚举。它不能扩展到考虑孤儿实现。 -
save_buffer_with_format
(如建议的 here )期望根据支持的颜色类型设置像素样本缓冲区。 - 即使是在特征
ImageEncoder
中声明的用于写入编码内容的裸图像编码器签名也需要遵循支持的颜色类型的像素缓冲区。
因此,使用支持的图像类型更加直接。将位图转换为 L8
颜色类型并使用其中的现有函数。
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(())
}
关于rust - 如何将位图切片的自定义图像实现转换为 PNG?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70065519/