Использование нескольких байтов для большей ширины пикселей
В предыдущем примере мы оставались простыми: использовали изображение шириной 8 пикселей, поэтому каждая строка представлялась одним байтом. Однако в реальных задачах может понадобиться больше пикселей. Как их представить? Можно использовать несколько байтов для более широких изображений. Но если так делать, как система поймёт, где столбцы, а где строки?
Именно поэтому в крейте embedded-graphics нужно указывать точную ширину. Указав ширину, система знает, сколько элементов массива использовать для представления строки. По этой ширине (и формату изображения) система затем определяет высоту.
Например, рассмотрим изображение разрешением 31x7 пикселей. Ширина — 31 пиксель, и каждый пиксель представлен 1 битом. Чтобы представить 31 пиксель в байтах, нужно вычислить, сколько байтов потребуется. Поскольку в байте 8 бит, делим общее количество пикселей (31) на 8. Получаем 3 полных байта, которые покрывают 24 пикселя, и ещё один байт для оставшихся 7 пикселей. Итого для 31 пикселя требуется 4 байта.
Крейт embedded-graphics внутри использует такой фрагмент для вычисления высоты. Мы не будем включать этот код в свой проект, но покажу его здесь для справки, чтобы продемонстрировать, как это работает внутри:
#![allow(unused)]
fn main() {
let height = data.len() / bytes_per_row(width, C::Raw::BITS_PER_PIXEL);
//...
//...
const fn bytes_per_row(width: u32, bits_per_pixel: usize) -> usize {
(width as usize * bits_per_pixel + 7) / 8
}
}
Здесь длина данных равна 28 (элементам массива), количество бит на пиксель — 1, а ширина изображения — 31. Если применить эту логику, получим bytes_per_row равным 4, а высоту — 7.
Вы можете запустить следующий код здесь же или в Rust Playground, чтобы разобраться в логике:
// 31x7 пикселей
#[rustfmt::skip]
const IMG_DATA: &[u8] = &[
// 1-я строка
0b00000001,0b11111111,0b11111111,0b00000000,
// 2-я строка
0b00000001,0b11111111,0b11111111,0b00000000,
//3-я строка
0b00000001,0b10000000,0b00000011,0b00000000,
//4-я строка
0b11111111,0b10000000,0b00000011,0b11111110,
//5-я строка
0b00000001,0b10000000,0b00000011,0b00000000,
//6-я строка
0b00000001,0b11111111,0b11111111,0b00000000,
//7-я строка
0b00000001,0b11111111,0b11111111,0b00000000,
];
const fn bytes_per_row(width: u32, bits_per_pixel: usize) -> usize {
(width as usize * bits_per_pixel + 7) / 8
}
fn main(){
const BITS_PER_PIXEL: usize = 1;
let width = 31;
let data = IMG_DATA;
println!("Bytes Per Row:{}", bytes_per_row(width,BITS_PER_PIXEL));
let height = data.len() / bytes_per_row(width, BITS_PER_PIXEL);
println!("Height: {}", height);
}
Создавать эти байтовые массивы вручную не нужно: можно воспользоваться онлайн-инструментом, например image2bytes, чтобы сгенерировать байтовый массив за вас.