sdfgen_lib/
lib.rs

1// Main image parsing and manipulation
2extern crate image;
3use image::GenericImageView;
4use image::GenericImage;
5
6//constants
7pub const WHITE: image::Rgba<u8> = image::Rgba([255u8, 255u8, 255u8, 255u8]);
8pub const INF: u32 = 9999999;
9
10/// Returns a vector of the coordinates in a given image.
11pub fn get_active(img: &image::DynamicImage) -> Vec<[u32;2]>{
12	let w = img.dimensions().0;
13	let h = img.dimensions().1;
14	let ws = w as usize;
15	let hs = h as usize;
16	let mut out = vec![[INF, INF];ws*hs];
17	let mut ind = 0;
18	let full = w*h;
19	for x in 0..w {
20		let _xs = x as usize;
21		for y in 0..h{
22			let _ys = y as usize;
23    		let pixel = img.get_pixel(y, x);
24    		if pixel == WHITE {
25//    			print!("#");
26    			out[ind] = [x, y];
27    		}
28    		else{
29//    			print!("_");
30    		}
31    		ind += 1;
32		}
33		let percent = (ind as f64)/(full as f64) * 100.0;
34		if percent % 10.0 == 0.0{
35			print!("[{}%]: {}/{} \r", percent as u32, ind, full);
36		}
37	}
38	println!("");
39	out
40}
41
42/// Finds the closest coordinate in the give coordinate list _active_.
43/// Returns and array of the size of 3. If secondpass is not enabled these will all be the same ( the closest coordinate).
44/// _second\_pass_ enables the search of three closest values, instead of just one.
45pub fn get_closest(active: &Vec<[u32; 2]>, value: &[u32; 2], second_pass: bool) -> [([u32; 2], u32); 3]{
46	let x = value[0] as f64;
47	let y = value[1] as f64;
48	let mut best = [INF, INF];
49	let mut bests= INF;
50	//Second pass
51	let mut best_l= [INF, INF];
52	let mut bests_l=INF;
53	//Third pass
54	let mut best_t = [INF, INF];
55	let mut bests_t=INF;
56	
57	for i in active{
58		let ix = i[0] as f64;
59		let iy = i[1] as f64;
60		let diff_x = (x - ix).abs() as u32;
61		let diff_y = (y - iy).abs() as u32;
62		let diff = diff_x + diff_y;
63		if diff < bests {
64			bests = diff;
65			best = *i;
66		}
67		else if second_pass && diff < bests_l{
68			bests_l = diff;
69			best_l= *i;
70		}
71		else if second_pass && diff < bests_t{
72			bests_t = diff;
73			best_t  = *i;
74		}
75	}
76	if second_pass{
77		return [(best, bests), (best_l, bests_l), (best_t, bests_t)];
78	}
79	return [(best, bests), (best, bests), (best, bests)];
80}
81
82/// Creates a black image with the dimensions of _img_.
83pub fn create_shadow_copy(img: &image::DynamicImage) -> image::DynamicImage{
84	let w = img.dimensions().0;
85	let h = img.dimensions().1;
86	image::DynamicImage::new_rgb8(w,h)
87}
88
89/// Generates a distance field from an image and an active map (obtained from get_active()).
90///
91/// _img_ is the input image,
92///
93/// _active_ the white pixels in the image,
94///
95/// _from_ coordinates where the reading of _img_ starts
96///
97/// _to_ coordinates where the reading of _img_ ends
98///
99/// _id_ simply an identifier for the console log. If this is not important to you just pass 0,
100///
101/// _scale_ the factor of the image read
102///
103/// The mapping of the output is all over the place.
104pub fn gen_sdf(img: &image::DynamicImage, active: &Vec<[u32; 2]>, from: [u32; 2], to: [u32; 2], id: u32, scale: u32) -> image::DynamicImage{
105//	let scale = 4;
106	let w = img.dimensions().0/scale;
107	let h = img.dimensions().1/scale;
108	let _ws = w as usize;
109	let _hs = h as usize;
110	
111	let mut to_x = to[0];
112	if to_x == 0{to_x = w;}
113	let mut to_y = to[1];
114	if to_y == 0{to_y = h;}
115	let w2 = to_x - from[0];
116	let h2 = to_y - from[1];
117
118	let mut out = create_shadow_copy(img);
119	
120	let full = w2*h2;
121	let max_dist = 255.0 / w2 as f64;
122	let mut ind = 0;
123	for x in from[0]..to_x {
124		let _xs = x as usize;
125		for y in from[1]..to_y{
126			let _ys = y as usize;
127			let closest = get_closest(&active, &[x*scale, y*scale], false);
128			let r = 255u8 - (closest[0].1 as f64 / max_dist) as u8;
129			let g = 255u8 - (closest[1].1 as f64 / max_dist) as u8;
130			let b = 255u8 - (closest[2].1 as f64 / max_dist) as u8;
131    		out.put_pixel(y, x, image::Rgba([r,g,b, 255]));
132    		//img.put_pixel(y*scale, x*scale, image::Rgba([r,r,r, 255])); //nice effect
133    		ind += 1;
134		}
135		let percent = ((ind as f64)/(full as f64) * 100.0) as u32;
136		if percent % 10 == 0{
137			print!("{}[{}%]: {}/{} \r", id, percent, ind, full);
138		}
139	}
140	println!("");
141	out
142}
143