Skip to content

Commit

Permalink
basic winit selection implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioRibera committed Jan 5, 2024
1 parent 7b0b050 commit e824241
Show file tree
Hide file tree
Showing 15 changed files with 479 additions and 68 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0"

[workspace]
resolver = "2"
members = ["crates/sss_lib", "crates/sss_cli"]
members = ["crates/sss_lib", "crates/sss_select", "crates/sss_cli"]

[profile.dev]
opt-level = 1
Expand All @@ -21,3 +21,4 @@ codegen-units = 1
[workspace.dependencies]
log = "0.4.20"
env_logger = "0.10.0"
thiserror = "1"
7 changes: 6 additions & 1 deletion crates/sss_cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[package]
name = "sss_cli"
version = "0.1.0"
edition = "2021"
edition.workspace = true
license.workspace = true

[[bin]]
name = "sss"
Expand All @@ -10,10 +11,14 @@ path = "./src/main.rs"
[dependencies]
screenshots = "0.8.6"
sss_lib = { path = "../sss_lib" }
sss_select = { path = "../sss_select" }
arboard = { version = "3.3.0", features = ["wayland-data-control"] }
clap = { version = "4.4.8", features = [
"derive",
"color",
"env",
"suggestions",
"wrap_help",
] }
wayland-client = "0.31.1"
wayland-protocols = { version = "0.31.0", features = ["client"] }
114 changes: 114 additions & 0 deletions crates/sss_cli/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use std::path::PathBuf;

use clap::Parser;
use sss_lib::image::{
error::{ImageFormatHint, UnsupportedError, UnsupportedErrorKind},
ImageError, ImageFormat,
};
use sss_lib::{Background, GenerationSettings, Shadow, ToRgba};
use sss_select::SelectConfig;

#[derive(Clone, Debug, Parser)]
#[clap(version, author)]
pub struct CliConfig {
#[clap(
long,
default_value = "false",
help = "When you take from a screen or window, capture the one on which the mouse is located."
)]
pub current: bool,
#[clap(long, default_value = "false", help = "Capture a full screen")]
pub screen: bool,
#[clap(long, default_value = "false", help = "Capture a application window")]
pub window: bool,
#[clap(long, default_value = "false", help = "Captures an area of the screen")]
pub area: bool,
// Screenshot Section
#[clap(
long,
short,
default_value = "#323232",
help = "Support: '#RRGGBBAA' 'h;#RRGGBBAA;#RRGGBBAA' 'v;#RRGGBBAA;#RRGGBBAA' or file path"
)]
pub background: String,
#[clap(long, short, default_value = "15")]
pub radius: u32,
// Padding Section
#[clap(long, default_value = "80")]
pub padding_x: u32,
#[clap(long, default_value = "100")]
pub padding_y: u32,
// Shadow Section
#[clap(
long,
default_value = "false",
help = "Generate shadow from inner image"
)]
pub shadow_image: bool,
#[clap(
long,
default_value = "#707070",
help = "Support: '#RRGGBBAA' '#RRGGBBAA;#RRGGBBAA' or file path"
)]
pub shadow_color: String,
#[clap(long, default_value = "50")]
pub shadow_blur: f32,
// Saving options
#[clap(long, short = 'c', help = "Send the result to your clipboard")]
pub just_copy: bool,
#[clap(
long,
default_value = "None",
help = "If it is set then the result will be saved here, otherwise it will not be saved."
)]
pub save_path: Option<PathBuf>,
#[clap(
long,
short = 'f',
default_value = "png",
help = "The format in which the image will be saved",
value_parser = str_to_format
)]
pub save_format: ImageFormat,
}

pub fn get_config() -> CliConfig {
CliConfig::parse()
}

impl Into<GenerationSettings> for CliConfig {
fn into(self) -> GenerationSettings {
let background = Background::try_from(self.background.clone()).unwrap();
GenerationSettings {
background: background.clone(),
padding: (self.padding_x, self.padding_y),
round_corner: Some(self.radius),
shadow: Some(Shadow {
background,
use_inner_image: self.shadow_image,
shadow_color: self.shadow_color.to_rgba().unwrap(),
blur_radius: self.shadow_blur,
}),
}
}
}

impl Into<SelectConfig> for CliConfig {
fn into(self) -> SelectConfig {
SelectConfig {
current: self.current,
screen: self.screen,
window: self.window,
area: self.area,
}
}
}

fn str_to_format(s: &str) -> Result<ImageFormat, ImageError> {
ImageFormat::from_extension(s).ok_or(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormatHint::Name(s.to_string()),
UnsupportedErrorKind::Format(ImageFormatHint::Name(s.to_string())),
),
))
}
30 changes: 23 additions & 7 deletions crates/sss_cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use sss_lib::{generate_image, DynImageContent, GenerationSettings, Shadow};
use config::get_config;
use sss_lib::{generate_image, DynImageContent};

mod config;

struct Screenshot;
struct Screenshot {
area: sss_select::Area,
}

impl DynImageContent for Screenshot {
fn content(&self) -> sss_lib::image::DynamicImage {
Expand All @@ -14,10 +17,23 @@ impl DynImageContent for Screenshot {
}

fn main() {
let img = generate_image(GenerationSettings {
shadow: Some(Shadow::default()),
..Default::default()
}, Screenshot);
let config = get_config();
let area = sss_select::get_area(config.clone().into());

let img = generate_image(config.clone().into(), Screenshot{ area });

img.save("./algo.png").unwrap();
if config.just_copy {
let mut c = arboard::Clipboard::new().unwrap();
c.set_image(arboard::ImageData {
width: img.width() as usize,
height: img.height() as usize,
bytes: std::borrow::Cow::Owned(img.to_vec()),
})
.unwrap();
return;
}

if let Some(path) = config.save_path {
img.save_with_format(path, config.save_format).unwrap();
}
}
5 changes: 3 additions & 2 deletions crates/sss_lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
[package]
name = "sss_lib"
version = "0.1.0"
edition = "2021"
edition.workspace = true
license.workspace = true

[dependencies]
log.workspace = true
env_logger.workspace = true
font-kit = "0.12.0"
thiserror.workspace = true
imageproc = "0.23.0"
arboard = { version = "3.3.0", features = ["wayland-data-control"] }
image = { version = "0.24.7", default-features = false, features = [
Expand Down
4 changes: 1 addition & 3 deletions crates/sss_lib/src/components/round.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use image::imageops::{crop_imm, resize, FilterType};
use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer, Rgba, RgbaImage};
use imageproc::drawing::{draw_filled_circle_mut, draw_line_segment_mut};
use image::{DynamicImage, GenericImage, GenericImageView, Rgba};

/// Round the corner of the image
pub fn round_corner(img: &mut DynamicImage, radius: u32) {
Expand Down
70 changes: 19 additions & 51 deletions crates/sss_lib/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,30 @@
use font_kit::error::{FontLoadingError, SelectionError};
use std::error::Error;
use std::fmt::{self, Display};
use std::num::ParseIntError;

#[derive(Debug)]
pub enum ImagenGeneration {
Font(Font),
Color(ParseColor),
}

#[derive(Debug)]
pub enum Font {
SelectionError(SelectionError),
FontLoadingError(FontLoadingError),
}

impl Error for Font {}

impl Display for Font {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Font::SelectionError(e) => write!(f, "Font error: {}", e),
Font::FontLoadingError(e) => write!(f, "Font error: {}", e),
}
}
}
use thiserror::Error;

impl From<SelectionError> for Font {
fn from(e: SelectionError) -> Self {
Font::SelectionError(e)
}
#[derive(Debug, Error)]
#[error(transparent)]
pub enum ImagenGeneration {
Color(#[from] ParseColor),
Background(#[from] Background),
}

impl From<FontLoadingError> for Font {
fn from(e: FontLoadingError) -> Self {
Font::FontLoadingError(e)
}
#[derive(Debug, Error)]
pub enum Background {
#[error("Cannot Parse Background from String")]
CannotParse,
#[error("Invalid format of String")]
InvalidFormat,
#[error("Invalid path of image")]
InvalidPath,
}

#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Error, Eq, PartialEq)]
pub enum ParseColor {
#[error("Invalid length of String")]
InvalidLength,
#[error("Invalid digit")]
InvalidDigit,
}

impl Error for ParseColor {}

impl Display for ParseColor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ParseColor::InvalidDigit => write!(f, "Invalid digit"),
ParseColor::InvalidLength => write!(f, "Invalid length"),
}
}
}

impl From<ParseIntError> for ParseColor {
fn from(_e: ParseIntError) -> Self {
ParseColor::InvalidDigit
}
#[error("Error parsing number")]
Parse(#[from] ParseIntError),
}
28 changes: 27 additions & 1 deletion crates/sss_lib/src/img.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use image::{Rgba, RgbaImage};

use crate::color::ToRgba;
use crate::components::round_corner;
// use crate::utils::copy_alpha;
use crate::error::Background as BackgroundError;
use crate::{DynImageContent, GenerationSettings};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -65,3 +65,29 @@ pub fn generate_image(

img
}

impl TryFrom<String> for Background {
type Error = BackgroundError;

fn try_from(value: String) -> Result<Self, Self::Error> {
if value.contains(";") {
let mut split = value.splitn(3, ";");
let o = split.next().unwrap();
let start = split.next().unwrap().to_rgba().unwrap();
let stop = split.next().unwrap().to_rgba().unwrap();
let orientation = if o == "h" {
GradientType::Horizontal
} else {
GradientType::Vertical
};
return Ok(Background::Gradient(orientation, start, stop))
}
if let Ok(color) = value.to_rgba() {
return Ok(Background::Solid(color));
}
if let Ok(img) = image::open(value) {
return Ok(Background::Image(img.to_rgba8()));
}
Err(BackgroundError::CannotParse)
}
}
1 change: 1 addition & 0 deletions crates/sss_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod utils;

pub use image;
pub use img::*;
pub use color::ToRgba;
pub use shadow::Shadow;

pub struct GenerationSettings {
Expand Down
2 changes: 1 addition & 1 deletion crates/sss_lib/src/shadow.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use image::{DynamicImage, Rgba, RgbaImage};
use image::{DynamicImage, Rgba};
use imageproc::drawing::draw_filled_rect_mut;
use imageproc::rect::Rect;

Expand Down
10 changes: 10 additions & 0 deletions crates/sss_select/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "sss_select"
version = "0.1.0"
edition.workspace = true
license.workspace = true

[dependencies]
raqote = "0.8.3"
winit = "0.29.8"
softbuffer = { version = "0.4.0", default-features = false, features = ["x11", "wayland"] }
Loading

0 comments on commit e824241

Please sign in to comment.