aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2019-12-08 03:23:16 +0100
committerDaniel Schadt <kingdread@gmx.de>2019-12-08 03:23:16 +0100
commit84dd675977b099b1ff79fe1589007cc8103c07ea (patch)
treec3f3fcd1a76666f80e5ca2972c9bf0eed98e03f1
parent8a05058090b470624994c6691e5169a362f9431d (diff)
downloadkondou-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.
-rw-r--r--src/render.rs84
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,
+ );
+}