Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use image::{DynamicImage, Rgb, RgbImage};
- use md5::{Digest, Md5};
- use std::env;
- const CHUNK_SIZE: usize = 3;
- const GRID_AREA: u8 = 25;
- #[derive(Default, Debug)]
- // some meta data about the identicon image to construct
- struct Image {
- hex: Vec<u8>,
- color: [u8; 3], // R,G,B
- // first element in pair is the hex with odd squares filtered out
- // second element is index of that elemen (before filtering)
- grid: Vec<(u8, u8)>,
- // collection of top_right and bottom_left coordinates to be used
- // in painting the canvas
- pixel_map: Vec<((u8, u8), (u8, u8))>,
- }
- fn main() {
- let args: Vec<String> = env::args().collect();
- let user_input = &args[1];
- println!("generating identicon for {user_input}");
- generate_identicon(user_input);
- }
- fn generate_identicon(user_input: &str) {
- // take user input and create identicon.
- // for reference from elixir
- // input
- // |> hash_input()
- // |> pick_color()
- // |> build_grid()
- // |> filter_odd_squares()
- // |> build_pixel_map()
- // |> draw_image()
- // |> save_image(input)
- //
- let input = user_input.as_bytes();
- let mut image: Image = Image {
- hex: hash_input(input),
- ..Default::default()
- };
- pick_color(&mut image);
- build_grid(&mut image);
- filter_odd_squares(&mut image);
- build_pixel_map(&mut image);
- let image_buffer = draw_image(&mut image);
- save_image(image_buffer, user_input);
- }
- fn save_image(image_buffer: RgbImage, user_input: &str) {
- // use user input as file name
- // simplest saving i found?
- let _ = DynamicImage::ImageRgb8(image_buffer).save(format!("{user_input}.png"));
- }
- fn draw_image(image: &mut Image) -> RgbImage {
- // step 1, create 250x250 canvas (image buffer) and then specify fill color
- // then fill each 50x50 square of pixel map with the color using the top_left
- // and bottom right x,y bounds from pixel map, then return the image buffer
- //
- let mut canvas = RgbImage::new(250, 250);
- let color = Rgb(image.color);
- // in our pixel map we have pair of top left and bottom right coords
- // that can define our x and y range in to iterate over to paint on
- for ((tlx, tly), (brx, bry)) in image.pixel_map.clone() {
- for x in tlx..brx {
- for y in tly..bry {
- // TODO change my struct to use u32 instead of u8 by default
- // so that i dont need .into()?
- canvas.put_pixel(x.into(), y.into(), color);
- }
- }
- }
- canvas
- }
- fn build_pixel_map(image: &mut Image) {
- // for ref
- // horizontal = (idx % 5) * 50;
- // vertical = (idx / 5) * 50;
- // top_left = (horizontal, vertical);
- // bottom_right = (horizontal + 50, vertical + 50);
- // return -> (top_left, bottom_right)
- image.pixel_map = image
- .grid
- .clone()
- .into_iter()
- .map(|(_, idx)| {
- (
- ((idx % 5) * 50, idx / 5 * 50),
- ((idx % 5) * 50 + 50, idx / 5 * 50 + 50),
- )
- })
- .collect();
- }
- fn filter_odd_squares(image: &mut Image) {
- // TODO: better way to do this?
- image.grid = image
- .grid
- .clone()
- .into_iter()
- .filter(|(x, _)| x % 2 == 0)
- .collect();
- }
- fn mirror_row(temp_grid: &mut Vec<Vec<u8>>) {
- // for every "row" of the grid, want to add the first two
- // elements to the last, in reverse order
- // e.g.
- // [1,2,3] -> [1,2,3,2,1]
- let mut temp_clone = temp_grid.clone();
- for (pos, row) in temp_grid.iter().enumerate() {
- temp_clone[pos].push(row[1]);
- temp_clone[pos].push(row[0]);
- }
- // deref kill the clone? TODO: is this necessary/efficient?
- *temp_grid = temp_clone;
- }
- fn build_grid(image: &mut Image) {
- let mut tmp: Vec<Vec<u8>> = vec![vec![]];
- tmp.pop(); //remove first [], TODO: better way to init the vec of vecs?
- for el in image.hex.chunks(CHUNK_SIZE) {
- if el.len() == CHUNK_SIZE {
- tmp.push(el.to_vec());
- }
- }
- // step 2, mirror row
- mirror_row(&mut tmp);
- // step 3, flatten grid
- let tmp_flat = tmp.into_iter().flatten().collect::<Vec<u8>>();
- // step 4, get index to pair with flattened grid
- let tmp_idx = (0..GRID_AREA).collect::<Vec<u8>>();
- // pair grid with idx
- image.grid = tmp_flat.clone().into_iter().zip(tmp_idx.clone()).collect();
- }
- fn hash_input(input: &[u8]) -> Vec<u8> {
- // this md-5 seems more verbose than the other regular md5 lib?
- // TODO: look into what the differences are later
- // let digest = md5::compute(b"qwerty");
- // vs
- // let digest = md5::Md5::new().update(b"qwerty")
- let mut digest2 = Md5::new();
- digest2.update(input);
- digest2.finalize().to_vec()
- }
- fn pick_color(image: &mut Image) {
- image.color.copy_from_slice(&image.hex[..3]);
- }
Advertisement
Add Comment
Please, Sign In to add comment