From 8a05058090b470624994c6691e5169a362f9431d Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Sun, 8 Dec 2019 02:53:34 +0100 Subject: add support for brightness gradients --- Cargo.toml | 1 + src/main.rs | 1 + src/render.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7407654..a2b7ae9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ md5 = "0.7" base64 = "0.11" termcolor = "1.0" num_enum = "0.4" +num-traits = "0.2" diff --git a/src/main.rs b/src/main.rs index b241eb5..5de9d56 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ extern crate imageproc; extern crate itertools; extern crate md5; extern crate num_enum; +extern crate num_traits; extern crate reqwest; extern crate rusttype; extern crate termcolor; diff --git a/src/render.rs b/src/render.rs index 437b66c..51f4ceb 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,7 +1,11 @@ use super::api::{Api, ApiError, Skill, Specialization, Trait}; use super::bt::{BuildTemplate, TraitChoice, Traitline}; -use image::{imageops, DynamicImage, GenericImage, GenericImageView, ImageBuffer, Rgba, RgbaImage}; +use image::{ + imageops, CatmullRom, DynamicImage, GenericImage, GenericImageView, ImageBuffer, Pixel, + Primitive, Rgba, RgbaImage, +}; use imageproc::drawing::{self, Point}; +use num_traits::NumCast; use rusttype::{Font, Scale, SharedBytes}; quick_error! { @@ -24,6 +28,8 @@ pub struct RenderOptions { traitline_height: u32, traitline_width: u32, traitline_brightness: i32, + traitline_use_gradient: bool, + traitline_gradient_size: u32, traitline_x_offset: u32, trait_size: u32, line_color: Rgba, @@ -43,6 +49,8 @@ impl Default for RenderOptions { traitline_height: 137, traitline_width: 647, traitline_brightness: 100, + traitline_use_gradient: true, + traitline_gradient_size: 50, traitline_x_offset: 200, trait_size: 30, line_color: Rgba([0, 0, 0, 255]), @@ -78,11 +86,7 @@ impl<'r> Renderer<'r> { pub fn new(api: &mut Api, options: RenderOptions) -> Renderer<'_> { let minor_mask = image::load_from_memory(include_bytes!("minor_trait_mask.png")) .expect("Mask image could not be loaded") - .resize( - options.trait_size, - options.trait_size, - imageops::FilterType::CatmullRom, - ); + .resize(options.trait_size, options.trait_size, CatmullRom); Renderer { api, options, @@ -100,7 +104,7 @@ impl<'r> Renderer<'r> { let img = self.api.get_image(&skill.icon)?.resize( self.options.skill_size, self.options.skill_size, - imageops::FilterType::CatmullRom, + CatmullRom, ); buffer.copy_from(&img, i as u32 * self.options.skill_size, 0); } @@ -116,7 +120,7 @@ impl<'r> Renderer<'r> { let minor_img = self.api.get_image(&minor.icon)?.resize( self.options.trait_size, self.options.trait_size, - imageops::FilterType::CatmullRom, + CatmullRom, ); let minor_img = with_mask(&minor_img, &self.minor_mask); let y_pos = (buffer.height() - minor_img.height()) / 2; @@ -138,7 +142,7 @@ impl<'r> Renderer<'r> { let major_img = self.api.get_image(&major.icon)?.resize( self.options.trait_size, self.options.trait_size, - imageops::FilterType::CatmullRom, + CatmullRom, ); let major_img = if !chosen { with_mask(&major_img.grayscale(), &major_img) @@ -225,7 +229,6 @@ impl<'r> Renderer<'r> { BG_CROP_WIDTH, BG_CROP_HEIGHT, ) - .brighten(self.options.traitline_brightness) .resize( self.options.traitline_width, self.options.traitline_height, @@ -233,6 +236,17 @@ impl<'r> Renderer<'r> { ) .to_rgba(); + if self.options.traitline_use_gradient { + buffer = brighten_gradient( + &buffer, + self.options.traitline_x_offset - self.options.traitline_gradient_size, + self.options.traitline_x_offset, + self.options.traitline_brightness, + ); + } else { + buffer = imageops::colorops::brighten(&buffer, self.options.traitline_brightness); + } + let minor_traits = self.api.get_traits(&spec.minor_traits)?; for minor in &minor_traits { self.render_minor_trait(&mut buffer, &minor)?; @@ -337,3 +351,48 @@ where Rgba([p[0], p[1], p[2], alpha]) }) } + +fn brighten_gradient( + image: &I, + start_x: u32, + end_x: u32, + value: i32, +) -> ImageBuffer> +where + I: GenericImageView, + P: Pixel + 'static, + S: Primitive + 'static, +{ + use image::math::utils::clamp; + let (width, height) = image.dimensions(); + let mut out = ImageBuffer::new(width, height); + + let max = S::max_value(); + let max: i32 = NumCast::from(max).unwrap(); + + for y in 0..height { + for x in 0..width { + let e = image.get_pixel(x, y).map_with_alpha( + |b| { + let interpol_value = if x < start_x { + 0 + } else if x > end_x { + value + } else { + let frac = (x - start_x) as f32 / (end_x - start_x) as f32; + (frac * value as f32).round() as i32 + }; + let c: i32 = NumCast::from(b).unwrap(); + let d = clamp(c + interpol_value, 0, max); + + NumCast::from(d).unwrap() + }, + |alpha| alpha, + ); + + out.put_pixel(x, y, e); + } + } + + out +} -- cgit v1.2.3