Skip to content

Commit

Permalink
Faster image processing.
Browse files Browse the repository at this point in the history
Does not store image to /tmp processes it in memory
  • Loading branch information
Supernovatux committed Aug 23, 2022
1 parent de001cc commit 19c03a4
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 49 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ simple_logger = "*"
clap-verbosity-flag = "*"
glob = "*"
ksni = "*"
fast_image_resize = "*"
tokio = { version = "*", features = ["full"]}
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Auto Backlight

Automatically change brightness depending on screen contents. The program takes a screenshot of the primary screen and calculates its average grayscale rgb value and increases/decreases the brightness by a certain value.
Automatically change brightness depending on screen contents. The program takes a screenshot of the primary screen and calculates its average RGB value and increases/decreases the brightness by a certain value.
## Installation

Git clone the repo and do a cargo build.
Expand All @@ -16,9 +16,7 @@ Git clone the repo and do a cargo build.
## Roadmap

- Improve performance.
- Effect of converting to grayscale is unknown
- [This](https://github.com/Cykooz/fast_image_resize) crate does linear image resize faster.
- Convert a `Vec[u8]` buffer of a png image directly to `DynamicImage`. Instead of writing to disk and loading it.
- Use grayscale and average just a single channel
- Make it cross platform.

## Related
Expand Down
10 changes: 5 additions & 5 deletions src/brightness.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use glob::glob;
use log::info;
use log::{error, info};

use std::fs::{read_to_string, write};
#[derive(Debug)]
Expand All @@ -18,7 +18,7 @@ impl BrightnessDevices {
};
devices.push(new_dev);
}
Err(e) => println!("{:?}", e),
Err(e) => error!("Glob error {:?}", e),
}
}
BrightnessDevices { devices }
Expand All @@ -33,7 +33,7 @@ impl BrightnessDevices {
.sum();
sum / self.devices.len() as i16
}
pub fn set_brightness(&self, change: i16) {
pub fn change_brightness(&self, change: i16) {
self.devices[0].increase_brightness(change)
}
}
Expand All @@ -50,14 +50,14 @@ impl BrightnessDevice {
.parse()
.unwrap()
}
pub fn get_current_brightness(&self) -> i16 {
fn get_current_brightness(&self) -> i16 {
read_to_string(&self.brightness)
.unwrap()
.trim()
.parse()
.unwrap()
}
fn get_current_brightness_percent(&self) -> i16 {
pub fn get_current_brightness_percent(&self) -> i16 {
let ret = (self.get_current_brightness() as f64 * 100.0 / self.get_max_brightness() as f64)
as i16;
info!("Current brightness is {}", ret);
Expand Down
26 changes: 2 additions & 24 deletions src/cli_parser.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
use std::fs;

use clap::Parser;
use clap_verbosity_flag::{InfoLevel, Verbosity};
use log::info;

#[derive(Parser, Debug, Clone)]
#[clap(author, version, about)]
pub struct Cli {
///Verbosity flag
#[clap(flatten)]
verbose: Verbosity<InfoLevel>,
///Path to store temp images
#[clap(
short,
long,
value_parser,
default_value_t = get_def_path(),
)]
pub path: String,
///Maximum and minimum change to brightness;
#[clap(short, long, value_parser, default_value_t = 10)]
pub limit: i16,
///Offset to limit. Use as --offset=<Value>
///Offset to limit. Use as --offset=<Value>
/// if limit=10
/// offset = -5
/// then brightness will vary between -15 to 5;
Expand All @@ -30,13 +20,6 @@ pub struct Cli {
#[clap(short, long, value_parser, default_value_t = 5)]
pub refresh: u64,
}
///Return path to password as [String]
///
/// If path was not provided by cli defaults to `~/.config/pass`
pub fn get_path() -> String {
let arg = init_cli();
arg.path
}
///Returns [log::Level] from verbosity flag passed via cli
///
/// Defaults to [log::Level::Info]
Expand All @@ -60,11 +43,6 @@ pub fn get_offset() -> i16 {
let arg = init_cli();
arg.offset
}
fn get_def_path() -> String {
fs::create_dir_all("/tmp/auto_backlight/screenshots").unwrap();
info!("Created /tmp/auto_backlight/screenshots");
String::from("/tmp/auto_backlight/screenshots/")
}
fn init_cli() -> Cli {
Cli::parse()
}
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ pub fn init() {
let log_lev = cli_parser::get_verbosity();
simple_logger::init_with_level(log_lev).unwrap();
info!("Starting with log_lev:- {:?}", log_lev);
std::env::set_current_dir(cli_parser::get_path()).unwrap();
}
8 changes: 4 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ async fn main() {
//User has changed brightness
if brightness != brightness_dev.get_brightness() + change {
brightness = brightness_dev.get_brightness();
brightness_dev.set_brightness(-change + change_new);
brightness_dev.change_brightness(-change + change_new);
} else {
brightness_dev.set_brightness(-change + change_new);
brightness_dev.change_brightness(-change + change_new);
}
change = change_new;
}
} else if change != 0 {
brightness_dev.set_brightness(-change);
brightness_dev.change_brightness(-change);
change = 0;
}
tokio::select! {
_ = interval.tick() => info!("Current brightness {}",brightness),
_ = &mut rx => {
brightness_dev.set_brightness(-change);
brightness_dev.change_brightness(-change);
break;},
}
}
Expand Down
37 changes: 26 additions & 11 deletions src/screens.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use image::{imageops::FilterType, DynamicImage, GenericImageView};
use fast_image_resize as fr;
use image::{DynamicImage, GenericImageView};
use log::{debug, info, trace};
use std::fs;
use std::num::NonZeroU32;

use crate::cli_parser::get_offset;

Expand All @@ -10,16 +11,31 @@ pub fn get_value_to_change(lim: u8, brightness: i16) -> i16 {
}

pub fn get_average_brightness(img: DynamicImage) -> i16 {
let img = img.resize(159, 100, FilterType::Nearest);
//Not sure if this is done properly but it works!
let width = NonZeroU32::new(img.width()).unwrap();
let height = NonZeroU32::new(img.height()).unwrap();
let src_image = fr::Image::from_vec_u8(
width,
height,
img.to_rgba8().into_raw(),
fr::PixelType::U8x4,
)
.unwrap();
let dst_width = NonZeroU32::new(160).unwrap();
let dst_height = NonZeroU32::new(100).unwrap();
let mut dst_image = fr::Image::new(dst_width, dst_height, fr::PixelType::U8x4);
let mut dst_view = dst_image.view_mut();
let mut resizer = fr::Resizer::new(fr::ResizeAlg::Nearest);
resizer.resize(&src_image.view(), &mut dst_view).unwrap();
let new = image::RgbaImage::from_vec(dst_width.get(), dst_height.get(), dst_image.into_vec())
.unwrap();
let img = image::DynamicImage::ImageRgba8(new);
let img = img.grayscale();
//Why does grayscale have RGBA. shouldn't two channels be sufficient?
let idk: Vec<u64> = img
let idk: Vec<u32> = img
.pixels()
.map(|x| (x.2[0] as u64 + x.2[1] as u64 + x.2[2] as u64) / 3)
.map(|x| (x.2[0] as u32 + x.2[1] as u32 + x.2[2] as u32) / 3)
.collect();
let sum: u64 = idk.iter().sum();
(sum / idk.len() as u64) as i16
let sum: u32 = idk.iter().sum();
(sum / idk.len() as u32) as i16
}
pub fn change_calc(lim: u8) -> i16 {
let screens = screenshots::Screen::all().unwrap();
Expand All @@ -28,8 +44,7 @@ pub fn change_calc(lim: u8) -> i16 {
if i.display_info.is_primary {
trace!("{:?}", i.display_info);
let img = i.capture().unwrap();
fs::write("tmp.png", &img.buffer()).unwrap();
let img = image::open("./tmp.png").unwrap();
let img = image::load_from_memory(img.buffer()).unwrap();
ch = get_average_brightness(img);
ch = get_value_to_change(lim, ch);
info!("Result of ch {}", ch);
Expand Down

0 comments on commit 19c03a4

Please sign in to comment.