Bitmap/Flood fill: Difference between revisions

Content added Content deleted
(Added Julia language)
(Added Rust version)
Line 2,282: Line 2,282:
bitmap.draw_circle(Pixel[200,100], 40, RGBColour::BLACK)
bitmap.draw_circle(Pixel[200,100], 40, RGBColour::BLACK)
bitmap.flood_fill(Pixel[140,160], RGBColour::BLUE)</lang>
bitmap.flood_fill(Pixel[140,160], RGBColour::BLUE)</lang>

=={{header|Rust}}==

<lang rust>
/* Naive Rust implementation of RosettaCode's Bitmap/Flood fill excercise.
*
* For the sake of simplicity this code reads PPM files (format specification can be found here: http://netpbm.sourceforge.net/doc/ppm.html ).
* The program assumes that the image has been created by GIMP in PPM ASCII mode and panics at any error.
*
* Also this program expects the input file to be in the same directory as the executable and named
* "input.ppm" and outputs a file in the same directory under the name "output.ppm".
*
*/

use std::fs::File; // Used for creating/opening files.
use std::io::{BufReader, BufRead, Write}; // Used for reading/writing files.

fn read_image(filename: String) -> Vec<Vec<(u8,u8,u8)>> {
let file = File::open(filename).unwrap();
let reader = BufReader::new(file);
let mut lines = reader.lines();

let _ = lines.next().unwrap(); // Skip P3 signature.
let _ = lines.next().unwrap(); // Skip GIMP comment.

let dimensions: (usize, usize) = {
let line = lines.next().unwrap().unwrap();
let values = line.split_whitespace().collect::<Vec<&str>>();

// We turn the &str vector that holds the width & height of the image into an usize tuplet.
(values[0].parse::<usize>().unwrap(),values[1].parse::<usize>().unwrap())
};

let _ = lines.next().unwrap(); // Skip maximum color value (we assume 255).

let mut image_data = Vec::with_capacity(dimensions.1);

for y in 0..dimensions.1 {
image_data.push(Vec::new());
for _ in 0..dimensions.0 {
// We read the R, G and B components and put them in the image_data vector.
image_data[y].push((lines.next().unwrap().unwrap().parse::<u8>().unwrap(),
lines.next().unwrap().unwrap().parse::<u8>().unwrap(),
lines.next().unwrap().unwrap().parse::<u8>().unwrap()));
}
}

image_data
}

fn write_image(image_data: Vec<Vec<(u8,u8,u8)>>) {
let mut file = File::create(format!("./output.ppm")).unwrap();

// Signature, then width and height, then 255 as max color value.
write!(file, "P3\n{} {}\n255\n", image_data.len(), image_data[0].len()).unwrap();

for row in &image_data {
// For performance reasons, we reserve a String with the necessary length for a line and
// fill that up before writing it to the file.

let mut line = String::with_capacity(row.len()*6); // 6 = r(space)g(space)b(space)
for (r,g,b) in row {

// &* is used to turn a String into a &str as needed by push_str.
line.push_str(&*format!("{} {} {} ", r,g,b));
}

write!(file, "{}", line).unwrap();
}

}

fn flood_fill(x: usize, y: usize, target: &(u8,u8,u8), replacement: &(u8,u8,u8), image_data: &mut Vec<Vec<(u8,u8,u8)>>) {
if &image_data[y][x] == target {
image_data[y][x] = *replacement;

if y > 0 {flood_fill(x,y-1, &target, &replacement, image_data);}
if x > 0 {flood_fill(x-1,y, &target, &replacement, image_data);}
if y < image_data.len()-1 {flood_fill(x,y+1, &target, &replacement, image_data);}
if x < image_data[0].len()-1 {flood_fill(x+1,y, &target, &replacement, image_data);}
}
}

fn main() {
let mut data = read_image(String::from("./input.ppm"));

flood_fill(1,50, &(255,255,255), &(0,255,0), &mut data); // Fill the big white circle with green.
flood_fill(40,35, &(0,0,0), &(255,0,0), &mut data); // Fill the small black circle with red.

write_image(data);

}</lang>


=={{header|Scala}}==
=={{header|Scala}}==