From d55f82ed1e85b4f005e4b75baa4d1a68508d330e Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Mon, 14 Jul 2025 17:52:19 +0200 Subject: [PATCH] Foo --- src/main.rs | 80 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/src/main.rs b/src/main.rs index d8be526..ffe5e18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use clap::Parser; -use eyre::{Context, ContextCompat, bail, eyre}; -use image::{DynamicImage, GrayImage, ImageReader, imageops::overlay}; +use eyre::{Context, ContextCompat, bail, ensure, eyre}; +use image::{DynamicImage, GrayAlphaImage, ImageReader, imageops::overlay}; use nix::ioctl_write_ptr; use std::{ fs::File, @@ -49,23 +49,19 @@ ioctl_write_ptr!( DrmRockchipEbcOffScreen ); -fn to_grayscale(path: &Path, image: DynamicImage) -> GrayImage { - if let DynamicImage::ImageLuma8(image) = image { +/// Convert [DynamicImage] into a [GrayAlphaImage]. +/// Note that we use [GrayAlphaImage] instead of `GrayImage` because we need the alpha channel to +/// be able to add stamps. +fn to_grayscale(path: &Path, image: DynamicImage) -> GrayAlphaImage { + if let DynamicImage::ImageLumaA8(image) = image { return image; } - eprintln!("Image {path:?} is not 8-bit grayscale. Converting..."); - image.to_luma8() + eprintln!("Image {path:?} is not 16-bit grayscale+alpha. Converting..."); + image.to_luma_alpha8() } -fn load_image(path: &Path) -> eyre::Result { - eprintln!("Opening image at {path:?}"); - - let image = ImageReader::open(path)?.decode()?; - Ok(to_grayscale(path, image)) -} - -fn load_wallpaper(path: &Path) -> eyre::Result { +fn load_wallpaper(path: &Path) -> eyre::Result { eprintln!("Opening image at {path:?}"); let mut image = ImageReader::open(path)?.decode()?; @@ -91,7 +87,7 @@ fn main() -> eyre::Result<()> { apply_stamp(stamp, &mut image)?; } - let pixels = image_to_offimage_buffer(image); + let pixels = image_to_offimage_buffer(image)?; let set_off_screen_data = DrmRockchipEbcOffScreen { info1: 0, // TODO: what is this? @@ -109,23 +105,41 @@ fn main() -> eyre::Result<()> { Ok(()) } -fn image_to_offimage_buffer(image: image::ImageBuffer, Vec>) -> Vec { - let mut pixels = image.into_vec(); +fn image_to_offimage_buffer(image: GrayAlphaImage) -> eyre::Result> { + let mut buf: Box<[u8; IOCTL_BUFFER_SIZE]> = vec![0u8; IOCTL_BUFFER_SIZE] + .into_boxed_slice() + .try_into() + .expect("Buffer is the correct size"); - // Convert 8-bit colorspace to 4-bits by truncating the 4 least significant bits. - // Yes, this means that the most-significant 4 bits of each byte are unused. - // Not idea why they designed it this way. Maybe it's faster? - for pixel in &mut pixels { - *pixel >>= 4; + let image = image.into_vec(); + + ensure!( + image.len() / 2 + 1 == IOCTL_BUFFER_SIZE, + "Invalid size of image backing buffer. Bug?", + ); + + // Iterate over pixels and copy them into `buf`. + for (i, pixel) in image.chunks_exact(2).enumerate() { + let &[gray, alpha] = pixel else { + unreachable!() + }; + + // ignore the alpha channel. + let _ = alpha; + + // Convert 8-bit colorspace to 4-bits by truncating the 4 least significant bits. + // Yes, this means that the most-significant 4 bits of each byte are unused. + // Not idea why they designed it this way. Maybe it's faster? + buf[i] = gray >> 4; } - // Add a null-terminator. No idea why this is necessary, but it is. - pixels.push(0u8); - // Sanity check buffer length - assert!(pixels.len() == IOCTL_BUFFER_SIZE); + assert_eq!(buf.len(), IOCTL_BUFFER_SIZE); - pixels + // Sanity-check that last byte is null. + assert_eq!(buf.last(), Some(&0u8)); + + Ok(buf) } fn parse_stamp(stamp: &str) -> Option<(i64, i64, &Path)> { @@ -138,13 +152,21 @@ fn parse_stamp(stamp: &str) -> Option<(i64, i64, &Path)> { Some((x, y, path)) } -fn apply_stamp(stamp: &str, onto: &mut GrayImage) -> eyre::Result<()> { +fn apply_stamp(stamp: &str, onto: &mut GrayAlphaImage) -> eyre::Result<()> { let (x, y, path) = parse_stamp(stamp).wrap_err_with(|| eyre!("Invalid stamp format: {stamp:?}"))?; - let image = load_image(path)?; + let image = load_stamp(path)?; overlay(onto, &image, x, y); Ok(()) } + +fn load_stamp(path: &Path) -> eyre::Result { + eprintln!("Opening image at {path:?}"); + + let image = ImageReader::open(path)?.decode()?; + + Ok(to_grayscale(path, image)) +}