Rust BMP图像处理库tinybmp的使用,tinybmp提供轻量高效的BMP格式解析与操作功能

Rust BMP图像处理库tinybmp的使用

tinybmp是一个小型BMP解析器,主要针对嵌入式、无标准库(no-std)环境设计,但也适用于任何场景。该库主要用于将BMP图像绘制到embedded_graphicsDrawTarget上,也可用于解析BMP文件用于其他应用。

示例

将BMP图像绘制到embedded-graphics绘图目标

使用Bmp结构体与embedded_graphicsImage结构体配合,可以在任何绘图目标上显示BMP文件。

use embedded_graphics::{image::Image, prelude::*};
use tinybmp::Bmp;

// 包含BMP文件数据
let bmp_data = include_bytes!("../tests/chessboard-8px-color-16bit.bmp");

// 解析BMP文件
let bmp = Bmp::from_slice(bmp_data).unwrap();

// 通过将图像包装在embedded-graphics `Image`中,在(10, 20)位置绘制图像
Image::new(&bmp, Point::new(10, 20)).draw(&mut display)?;

使用像素迭代器

Bmp::pixels方法返回一个遍历BMP文件中所有像素的迭代器。BMP文件中的颜色会自动转换为embedded_graphics中的一种颜色类型。

use embedded_graphics::{pixelcolor::Rgb888, prelude::*};
use tinybmp::Bmp;

// 包含BMP文件数据
let bmp_data = include_bytes!("../tests/chessboard-8px-24bit.bmp");

// 解析BMP文件
// 注意需要明确指定BMP文件中颜色将转换为何种颜色类型
let bmp = Bmp::<Rgb888>::from_slice(bmp_data).unwrap();

for Pixel(position, color) in bmp.pixels() {
    println!("R: {}, G: {}, B: {} @ ({})", color.r(), color.g(), color.b(), position);
}

访问单个像素

Bmp::pixel可用于获取单个像素的颜色。返回的颜色将自动转换为embedded_graphics中的一种颜色类型。

use embedded_graphics::{pixelcolor::Rgb888, image::GetPixel, prelude::*};
use tinybmp::Bmp;

// 包含BMP文件数据
let bmp_data = include_bytes!("../tests/chessboard-8px-24bit.bmp");

// 解析BMP文件
// 注意需要明确指定BMP文件中颜色将转换为何种颜色类型
let bmp = Bmp::<Rgb888>::from_slice(bmp_data).unwrap();

let pixel = bmp.pixel(Point::new(3, 2));

assert_eq!(pixel, Some(Rgb888::WHITE));

注意:目前在使用RLE4或RLE8压缩索引位图时无法访问单个像素。对于这些格式,pixel()函数将始终返回None

访问原始图像数据

对于大多数应用来说,Bmp提供的高级访问已经足够。但如果需要更低级别的访问,可以使用RawBmp结构体来访问BMP头信息和颜色表。

use embedded_graphics::prelude::*;
use tinybmp::{RawBmp, Bpp, Header, RawPixel, RowOrder, CompressionMethod};

let bmp = RawBmp::from_slice(include_bytes!("../tests/chessboard-8px-24bit.bmp"))
    .expect("Failed to parse BMP image");

// 读取BMP头
assert_eq!(
    bmp.header(),
    &Header {
        file_size: 314,
        image_data_start: 122,
        bpp: Bpp::Bits24,
        image_size: Size::new(8, 8),
        image_data_len: 192,
        channel_masks: None,
        row_order: RowOrder::BottomUp,
        compression_method: CompressionMethod::Rgb,
    }
);

// 获取图像像素坐标和值的迭代器并收集到向量中
let pixels: Vec<RawPixel> = bmp.pixels().collect();

// 示例图像为8x8px
assert_eq!(pixels.len(), 8 * 8);

// 也可以读取单个原始像素值
let pixel = bmp.pixel(Point::new(3, 2));

// 源图像中白色像素的原始值
assert_eq!(pixel, Some(0xFFFFFFu32));

完整示例代码

// 示例1: 绘制BMP图像到显示设备
use embedded_graphics::{image::Image, prelude::*};
use tinybmp::Bmp;

fn draw_bmp_to_display(display: &mut impl DrawTarget) -> Result<(), Box<dyn std::error::Error>> {
    // 包含BMP文件数据
    let bmp_data = include_bytes!("chessboard-8px-color-16bit.bmp");
    
    // 解析BMP文件
    let bmp = Bmp::from_slice(bmp_data)?;
    
    // 在(10, 20)位置绘制图像
    Image::new(&bmp, Point::new(10, 20)).draw(display)?;
    
    Ok(())
}

// 示例2: 遍历像素信息
use embedded_graphics::{pixelcolor::Rgb888, prelude::*};

fn analyze_bmp_pixels() {
    let bmp_data = include_bytes!("chessboard-8px-24bit.bmp");
    let bmp = Bmp::<Rgb888>::from_slice(bmp_data).unwrap();
    
    for Pixel(pos, color) in bmp.pixels() {
        println!("Position: {:?}, Color: R:{}, G:{}, B:{}", 
                pos, color.r(), color.g(), color.b());
    }
}

// 示例3: 访问原始BMP数据
fn inspect_raw_bmp() {
    let bmp = RawBmp::from_slice(include_bytes!("chessboard-8px-24bit.bmp")).unwrap();
    
    println!("BMP Header: {:?}", bmp.header());
    println!("First pixel color: {:?}", bmp.pixel(Point::new(0, 0)));
}

安装

在项目目录中运行以下Cargo命令:

cargo add tinybmp

或者在Cargo.toml中添加以下行:

tinybmp = "0.6.0"

最低支持的Rust版本

tinybmp最低支持的Rust版本为1.71或更高。


1 回复

Rust BMP图像处理库tinybmp使用指南

简介

tinybmp是一个轻量级的Rust库,专门用于解析和操作BMP(位图)图像格式。它设计简洁高效,特别适合嵌入式系统和资源受限环境中的BMP图像处理需求。

主要特性

  • 支持多种BMP格式解析
  • 低内存占用
  • 无标准库依赖(no_std兼容)
  • 简单的API设计

使用方法

添加依赖

首先在Cargo.toml中添加tinybmp依赖:

[dependencies]
tinybmp = "0.7.0"

基本用法

解析BMP文件

use tinybmp::{Bmp, FileType, RawBmp};

// 从字节切片解析BMP
let bmp_data = include_bytes!("../tests/chessboard-8px-24bit.bmp");
let bmp = Bmp::from_slice(bmp_data).unwrap();

// 获取图像基本信息
println!("尺寸: {}x{}", bmp.width(), bmp.height());
println!("颜色深度: {}bpp", bmp.bpp());

访问像素数据

// 遍历所有像素
for pixel in bmp.pixels() {
    println!("坐标: ({}, {}), 颜色: {:?}", pixel.x, pixel.y, pixel.color);
}

// 获取特定位置像素
if let Some(pixel) = bmp.try_get_pixel(10, 20) {
    println!("(10,20)处像素: {:?}", pixel);
}

创建新BMP图像

use tinybmp::{Bmp, BmpBuilder, PixelColor};
use embedded_graphics::pixelcolor::Rgb888;

// 创建一个16x16的24位BMP
let mut builder = BmpBuilder::new()
    .with_size(16, 16)
    .with_bpp(24);

// 填充像素数据
for y in 0..16 {
    for x in 0..16 {
        let color = if (x + y) % 2 == 0 {
            Rgb888::new(255, 0, 0) // 红色
        } else {
            Rgb888::new(0, 0, 255) // 蓝色
        };
        builder.set_pixel(x, y, color).unwrap();
    }
}

// 生成BMP数据
let bmp_data = builder.build().unwrap();

与embedded-graphics集成

use embedded_graphics::{prelude::*, pixelcolor::Rgb888};
use tinybmp::Bmp;

let bmp_data = include_bytes!("../tests/chessboard-8px-24bit.bmp");
let bmp = Bmp::<Rgb888>::from_slice(bmp_data).unwrap();

// 在embedded-graphics中使用
display.draw_iter(bmp.pixels()).unwrap();

高级用法

处理不同颜色深度的BMP

use tinybmp::{Bmp, DynamicBmp};

// 自动检测颜色深度
let dynamic_bmp = DynamicBmp::from_slice(bmp_data).unwrap();

match dynamic_bmp {
    DynamicBmp::Rgb16(bmp) => {
        println!("16位RGB图像");
        // 处理16位图像...
    }
    DynamicBmp::Rgb24(bmp) => {
        println!("24位RGB图像");
        // 处理24位图像...
    }
    DynamicBmp::Rgb32(bmp) => {
        println!("32位RGB图像");
        // 处理32位图像...
    }
}

性能优化

let bmp = Bmp::from_slice(bmp_data).unwrap();

for y in 0..bmp.height() {
    let row = bmp.row(y).unwrap();
    for (x, pixel) in row.enumerate() {
        // 处理每个像素...
    }
}

注意事项

  1. tinybmp主要设计用于解析,对BMP创建的完整功能支持有限
  2. 对于非常规BMP格式可能支持不完整
  3. 在资源受限环境中使用时,注意检查解析结果

完整示例

以下是一个完整的BMP图像处理示例,包含读取、修改和保存功能:

use tinybmp::{Bmp, BmpBuilder, DynamicBmp};
use embedded_graphics::pixelcolor::Rgb888;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 读取BMP文件
    let bmp_data = include_bytes!("image.bmp");
    let bmp = DynamicBmp::from_slice(bmp_data)?;
    
    // 2. 打印图像信息
    println!("图像信息:");
    match &bmp {
        DynamicBmp::Rgb16(bmp) => {
            println!("格式: 16位RGB");
            println!("尺寸: {}x{}", bmp.width(), bmp.height());
        }
        DynamicBmp::Rgb24(bmp) => {
            println!("格式: 24位RGB"); 
            println!("尺寸: {}x{}", bmp.width(), bmp.height());
        }
        DynamicBmp::Rgb32(bmp) => {
            println!("格式: 32位RGB");
            println!("尺寸: {}x{}", bmp.width(), bmp.height());
        }
    }
    
    // 3. 创建新图像(反转颜色)
    let mut builder = BmpBuilder::new()
        .with_size(bmp.width(), bmp.height())
        .with_bpp(24);
        
    for y in 0..bmp.height() {
        for x in 0..bmp.width() {
            let pixel = bmp.try_get_pixel(x, y)?;
            let inverted = Rgb888::new(
                255 - pixel.r(),
                255 - pixel.g(), 
                255 - pixel.b()
            );
            builder.set_pixel(x, y, inverted)?;
        }
    }
    
    // 4. 保存新图像
    let new_bmp = builder.build()?;
    std::fs::write("inverted.bmp", new_bmp.as_slice())?;
    
    println!("图像处理完成,已保存为 inverted.bmp");
    Ok(())
}

这个完整示例展示了如何:

  1. 读取BMP文件并自动检测其格式
  2. 获取图像的基本信息
  3. 创建新图像并对每个像素进行颜色反转处理
  4. 将处理后的图像保存到新文件

tinybmp是一个在Rust生态中处理BMP图像的轻量级解决方案,特别适合需要高效解析BMP而不需要复杂图像处理功能的场景。

回到顶部