diff options
author | Daniel Schadt <kingdread@gmx.de> | 2019-12-08 03:23:16 +0100 |
---|---|---|
committer | Daniel Schadt <kingdread@gmx.de> | 2019-12-08 03:23:16 +0100 |
commit | 84dd675977b099b1ff79fe1589007cc8103c07ea (patch) | |
tree | c3f3fcd1a76666f80e5ca2972c9bf0eed98e03f1 /src/render.rs | |
parent | 8a05058090b470624994c6691e5169a362f9431d (diff) | |
download | kondou-84dd675977b099b1ff79fe1589007cc8103c07ea.tar.gz kondou-84dd675977b099b1ff79fe1589007cc8103c07ea.tar.bz2 kondou-84dd675977b099b1ff79fe1589007cc8103c07ea.zip |
improve antialiasing of thick lines
As it turns out, the algorithm for drawing convex polygons is very bad
at handling aliasing, and the line height looked off as well. The new
algorithm fixes the issue by first drawing a horizontal filled
rectangle, then rotating the rectangle by the required angle (using
bicubic filtering) and finally overlaying the rectangle onto the target.
This improves both the looks of the line height and the aliasing
effects.
Diffstat (limited to 'src/render.rs')
-rw-r--r-- | src/render.rs | 84 |
1 files changed, 55 insertions, 29 deletions
diff --git a/src/render.rs b/src/render.rs index 51f4ceb..53edd2c 100644 --- a/src/render.rs +++ b/src/render.rs @@ -4,9 +4,10 @@ use image::{ imageops, CatmullRom, DynamicImage, GenericImage, GenericImageView, ImageBuffer, Pixel, Primitive, Rgba, RgbaImage, }; -use imageproc::drawing::{self, Point}; +use imageproc::drawing; use num_traits::NumCast; use rusttype::{Font, Scale, SharedBytes}; +use std::cmp::min; quick_error! { #[derive(Debug)] @@ -175,44 +176,26 @@ impl<'r> Renderer<'r> { + (x_slice + self.options.trait_size) / 2 + self.options.traitline_x_offset; let end_x = start_x + x_slice - self.options.trait_size; - let start_y = (buffer.height() - self.options.line_height) / 2; + let start_y = buffer.height() / 2; let y_slice = buffer.height() / 3; - let end_y = y_slice * (choice as u32 - 1) + (y_slice - self.options.line_height) / 2; + let end_y = y_slice * (choice as u32 - 1) + y_slice / 2; - drawing::draw_convex_polygon_mut( + draw_thick_line( buffer, - &[ - Point::new(start_x as i32, start_y as i32), - Point::new( - start_x as i32, - start_y as i32 + self.options.line_height as i32, - ), - Point::new(end_x as i32, end_y as i32 + self.options.line_height as i32), - Point::new(end_x as i32, end_y as i32), - ], + (start_x, start_y), + (end_x, end_y), + self.options.line_height, self.options.line_color, ); if tier == 2 { return Ok(()); } - drawing::draw_convex_polygon_mut( + draw_thick_line( buffer, - &[ - Point::new( - 2 * x_slice as i32 + start_x as i32 - self.options.trait_size as i32, - start_y as i32, - ), - Point::new( - 2 * x_slice as i32 + start_x as i32 - self.options.trait_size as i32, - start_y as i32 + self.options.line_height as i32, - ), - Point::new( - self.options.trait_size as i32 + end_x as i32, - end_y as i32 + self.options.line_height as i32, - ), - Point::new(self.options.trait_size as i32 + end_x as i32, end_y as i32), - ], + (end_x + self.options.trait_size, end_y), + (end_x + x_slice, start_y), + self.options.line_height, self.options.line_color, ); @@ -396,3 +379,46 @@ where out } + +fn draw_thick_line<I>( + image: &mut I, + start: (u32, u32), + end: (u32, u32), + thickness: u32, + color: I::Pixel, +) where + I: GenericImage<Pixel = Rgba<u8>>, +{ + let delta_x = end.0 as i32 - start.0 as i32; + let delta_y = end.1 as i32 - start.1 as i32; + let line_length = ((delta_x * delta_x + delta_y * delta_y) as f32) + .sqrt() + .round() as u32; + + let mut line_buffer: RgbaImage = ImageBuffer::new(line_length, line_length); + let halfway = (line_length - thickness) / 2; + + for i in 0..thickness { + for x in 0..line_length { + let y = halfway + i; + line_buffer.put_pixel(x, y, color); + } + } + + line_buffer = imageproc::geometric_transformations::rotate_about_center( + &line_buffer, + (delta_y as f32 / delta_x as f32).atan(), + imageproc::geometric_transformations::Interpolation::Bicubic, + Rgba([0, 0, 0, 0]), + ); + + let half_x = (start.0 as i32 + delta_x / 2) as u32; + let half_y = (start.1 as i32 + delta_y / 2) as u32; + + imageops::overlay( + image, + &line_buffer, + half_x - line_length / 2, + half_y - line_length / 2, + ); +} |