Reputation: 9711
I want to draw a line in a bitmap, e.g. from pixel (10, 10) to pixel (90, 90). The line must have a specific width.
Using piston image, I am able to draw a single pixel:
let mut image = ImageBuffer::<image::Rgb<u8>>::new(100, 100);
image.get_pixel_mut(5, 5).data = [255, 255, 255];
image.save("output.png");
However there is no method to draw a line.
I suppose I have to use piston::graphics for that, but I can’t find any ressource how to do it (any example involves a window that provides a context on which graphics works on).
Upvotes: 5
Views: 3657
Reputation: 5062
In addition to the great answer above: there is now direct support for drawing lines and many more shapes (even texts) in the imageproc library (see also the examples there):
extern crate image;
extern crate imageproc;
use image::{Rgb, RgbImage};
use imageproc::drawing::draw_line_segment_mut;
fn main() {
let mut img = RgbImage::new(100, 100);
draw_line_segment_mut(
&mut img,
(5f32, 5f32), // start point
(95f32, 95f32), // end point
Rgb([69u8, 203u8, 133u8]), // RGB colors
);
img.save("output.png").unwrap();
}
Upvotes: 5
Reputation: 19452
If you drop the width requirement and don't need antialiasing either, you could use something like Bresenham's line algorithm (also on Rosetta Code):
extern crate image;
use image::RgbImage;
fn draw_line(img: &mut RgbImage, x0: i64, y0: i64, x1: i64, y1: i64) {
// Create local variables for moving start point
let mut x0 = x0;
let mut y0 = y0;
// Get absolute x/y offset
let dx = if x0 > x1 { x0 - x1 } else { x1 - x0 };
let dy = if y0 > y1 { y0 - y1 } else { y1 - y0 };
// Get slopes
let sx = if x0 < x1 { 1 } else { -1 };
let sy = if y0 < y1 { 1 } else { -1 };
// Initialize error
let mut err = if dx > dy { dx } else {-dy} / 2;
let mut err2;
loop {
// Set pixel
img.get_pixel_mut(x0 as u32, y0 as u32).data = [255, 255, 255];
// Check end condition
if x0 == x1 && y0 == y1 { break };
// Store old error
err2 = 2 * err;
// Adjust error and start position
if err2 > -dx { err -= dy; x0 += sx; }
if err2 < dy { err += dx; y0 += sy; }
}
}
fn main() {
let mut img = RgbImage::new(256, 256);
draw_line(&mut img, 10, 10, 246, 128);
draw_line(&mut img, 128, 10, 10, 246);
img.save("output.png").unwrap();
}
Output:
As a primitive form of adding thickness, you could repeat drawing the line with some offset. Alternatively, draw a filled rectangle where the height of the rectangle corresponds to the thickness of the desired line.
There's a ticket open in the imageproc project to add anti aliased line drawing support: https://github.com/PistonDevelopers/imageproc/issues/97
Upvotes: 5