From 68ecb118a9314e3fdc5ba04b7bea0ccab6cee40b Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 4 Oct 2020 10:41:46 -0500 Subject: [PATCH] Added RST image parsing + Added DIP project --- src/main.rs | 31 +++--- src/rst_parser.rs | 32 ------ src/rst_parser/mod.rs | 111 ++++++++++++++++++++ src/rst_parser/rst_error.rs | 28 +++++ static/raw_rst/projects/motion_detector.rst | 33 ++++++ static/raw_rst/projects/website.rst | 5 +- templates/listing.html.tera | 2 +- 7 files changed, 191 insertions(+), 51 deletions(-) delete mode 100644 src/rst_parser.rs create mode 100644 src/rst_parser/mod.rs create mode 100644 src/rst_parser/rst_error.rs create mode 100644 static/raw_rst/projects/motion_detector.rst diff --git a/src/main.rs b/src/main.rs index 2d67a4d..8b36cbe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,9 +5,10 @@ extern crate rocket; #[macro_use] extern crate serde_derive; -mod rst_parser; mod tests; +mod rst_parser; +use crate::rst_parser::parse_images; use regex::Regex; use rocket::Request; use rocket_contrib::serve::StaticFiles; @@ -16,9 +17,9 @@ use rst_parser::parse_links; use std::collections::HashMap; use std::error; use std::fmt; -use std::path::{PathBuf, Path}; -use std::{fs, io}; use std::io::Error; +use std::path::{Path, PathBuf}; +use std::{fs, io}; type PageResult = std::result::Result; @@ -117,7 +118,7 @@ fn get_pages(path: &str, pages: &mut Vec) -> io::Result<()> { } else { match rank.parse() { Ok(r) => r, - Err(_) => std::u32::MAX + Err(_) => std::u32::MAX, } }; @@ -144,16 +145,15 @@ fn get_pages(path: &str, pages: &mut Vec) -> io::Result<()> { /// * `page_name` - file to look for fn get_page(path: &Path) -> PageResult { let file_name = path.file_name().ok_or(PageNotFoundError)?; - let file_name = file_name.to_str().ok_or(PageNotFoundError)?.to_string(); + let file_name = file_name.to_str().ok_or(PageNotFoundError)?.to_string(); if path.exists() { return Ok(SiteFile { rank: 0, file_name: file_name.clone(), link_name: file_name, - path: path.to_path_buf() - }) - } - else { + path: path.to_path_buf(), + }); + } else { let mut dir_path = path.to_path_buf(); dir_path.pop(); @@ -166,8 +166,8 @@ fn get_page(path: &Path) -> PageResult { rank: 0, file_name: entry_name, link_name: file_name, - path: entry.path() - }) + path: entry.path(), + }); } } } @@ -191,9 +191,7 @@ fn rst_page(page: PathBuf) -> Template { path.push(page); // Try and get the page - let site_page = match get_page( - path.as_path() - ) { + let site_page = match get_page(path.as_path()) { Ok(site_page) => site_page, Err(_) => { return error_page(path.to_str().unwrap()); @@ -206,7 +204,7 @@ fn rst_page(page: PathBuf) -> Template { let mut sub_files: Vec = Vec::new(); match get_pages(site_page.path.to_str().unwrap(), &mut sub_files) { Ok(_) => (), - Err(_) => return error_page(&site_page.link_name) + Err(_) => return error_page(&site_page.link_name), } let page_data = PageData { @@ -229,7 +227,8 @@ fn rst_page(page: PathBuf) -> Template { }; // Render links - let mut contents = parse_links(&contents); + let mut contents = parse_links(&contents).unwrap(); + contents = parse_images(contents.as_str()).unwrap(); // Ensure render will look good contents = contents.replace("\n", "
"); diff --git a/src/rst_parser.rs b/src/rst_parser.rs deleted file mode 100644 index d4cf160..0000000 --- a/src/rst_parser.rs +++ /dev/null @@ -1,32 +0,0 @@ -use regex::{Regex, Captures}; -use std::collections::HashMap; - -/// Renders RST links as HTML links -/// -/// # Arguments -/// -/// * `string` - input RST string -/// -pub fn parse_links(string: &str) -> String { - let re_link_ref = Regex::new(r"\n?.. _(.*): (.*)\n").unwrap(); - let mut link_map: HashMap = HashMap::new(); - - for cap in re_link_ref.captures_iter(string) { - link_map.insert(String::from(&cap[1]), String::from(&cap[2])); - } - - let text: String = re_link_ref.replace_all(string, "").to_string(); - - let re_link = Regex::new(r"`(.*)`_").unwrap(); - - let output = re_link.replace_all(&text, |cap: &Captures| { - let link = match link_map.get(&cap[1]) { - None => String::from(""), - Some(link) => link.to_owned(), - }; - - format!("{}", link, &cap[1]) - }); - - output.to_string() -} diff --git a/src/rst_parser/mod.rs b/src/rst_parser/mod.rs new file mode 100644 index 0000000..56f1520 --- /dev/null +++ b/src/rst_parser/mod.rs @@ -0,0 +1,111 @@ +pub mod rst_error; + +use regex::{Captures, Regex}; +use std::collections::HashMap; +use rst_error::RSTError; +use std::convert::TryFrom; + +/// RST Image +struct RSTImage { + /// File location + image_file: String, + /// Height + height: Option, + /// Width + width: Option, + /// Alt Text + alt: Option, + /// Align (not implemented) + #[allow(dead_code)] + align: Option, +} + +impl RSTImage { + /// Convert to HTML img tag + fn to_html(&self) -> String { + let mut html = format!("", html, style); + + html + } +} + +impl TryFrom<&Captures<'_>> for RSTImage { + type Error = RSTError; + /// Convert from a regex capture to a RSTImage + /// + /// # Arguments + /// + /// * cap - regex capture + fn try_from(cap: &Captures<'_>) -> Result { + let image = Self { + image_file: cap + .name("file_name") + .map(|m| m.as_str().to_string()) + .ok_or(RSTError::NotFound("file_name"))?, + height: cap.name("width").map(|m| m.as_str().to_string()), + width: cap.name("width").map(|m| m.as_str().to_string()), + alt: cap.name("alt").map(|m| m.as_str().to_string()), + align: cap.name("align").map(|m| m.as_str().to_string()), + }; + + Ok(image) + } +} + +/// Renders RST links as HTML links +/// +/// # Arguments +/// +/// * `string` - input RST string +pub fn parse_links(string: &str) -> Result { + let re_link_ref = Regex::new(r"\n?.. _(.*): (.*)\n")?; + let mut link_map: HashMap = HashMap::new(); + + for cap in re_link_ref.captures_iter(string) { + link_map.insert(String::from(&cap[1]), String::from(&cap[2])); + } + + let text: String = re_link_ref.replace_all(string, "").to_string(); + + let re_link = Regex::new(r"`(.*)`_")?; + + let output = re_link.replace_all(&text, |cap: &Captures| { + let link = match link_map.get(&cap[1]) { + None => String::from(""), + Some(link) => link.to_owned(), + }; + + format!("{}", link, &cap[1]) + }); + + Ok(output.to_string()) +} + +/// Renders RST images as HTML embedded images +/// +/// # Arguments +/// +/// * `string` - input rst string +pub fn parse_images(string: &str) -> Result { + let re_image = Regex::new( + r".. image:: (?P.*)\n( *((:height: (?P.*))|(:width: (?P.*))|(:scale: (?P.*%))|(:alt: (?P.*))|(:align: (?P.*)))\n)*", + )?; + + Ok(re_image + .replace_all(string, |cap: &Captures| RSTImage::try_from(cap).unwrap().to_html()) + .to_string()) +} diff --git a/src/rst_parser/rst_error.rs b/src/rst_parser/rst_error.rs new file mode 100644 index 0000000..7531867 --- /dev/null +++ b/src/rst_parser/rst_error.rs @@ -0,0 +1,28 @@ +use regex::Error; + +#[derive(Debug)] +pub enum RSTError { + /// Regex compile error + RegexError(regex::Error), + /// Required element not found + NotFound(&'static str), +} + +impl std::error::Error for RSTError {} + +impl From for RSTError { + /// From regex error + fn from(e: Error) -> Self { + Self::RegexError(e) + } +} + +impl std::fmt::Display for RSTError { + /// fmt error + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + RSTError::NotFound(s) => write!(f, "required element missing: `{}`", s), + RSTError::RegexError(e) => write!(f, "regex compile error: `{:?}`", e), + } + } +} \ No newline at end of file diff --git a/static/raw_rst/projects/motion_detector.rst b/static/raw_rst/projects/motion_detector.rst new file mode 100644 index 0000000..84f5eeb --- /dev/null +++ b/static/raw_rst/projects/motion_detector.rst @@ -0,0 +1,33 @@ +Motion Detector +=============== +A project made for Auburn ELEC 7450: Digtal Image Processing. The source code can be found on my `Github`_ + +.. _GitHub: https://github.com/joeyahines/motion_detector + +Goal +++++ +The goal of this project was to detect motion on a video stream from a `VideoForLinux`_ source. The algorithm +can also be tested by loading in individual frames. + +.. _VideoForLinux: https://en.wikipedia.org/wiki/Video4Linux + +Implementation +++++++++++++++ +The project was written in C and VideoForLinux for grabbing image data and `SDL`_ for rendering the video +output. A background model is built by implementing a moving average of the image. In addition to this, +a motion mask is implemented to desensitise the algorithm from background motion objects. + +.. _SDL: https://www.libsdl.org/ + +Webcam output w/ motion highlighted: + +.. image:: https://github.com/joeyahines/motion_detector/blob/master/docs/final_report/motion.png?&raw=true + :width: 60% + :height: auto + +Motion detection layer: + +.. image:: https://github.com/joeyahines/motion_detector/blob/master/docs/final_report/motion_image.png?raw=true + :width: 60% + :height: auto + diff --git a/static/raw_rst/projects/website.rst b/static/raw_rst/projects/website.rst index 5ba61cb..80758a2 100644 --- a/static/raw_rst/projects/website.rst +++ b/static/raw_rst/projects/website.rst @@ -42,5 +42,6 @@ improving how the site looked on mobile. Future Improvements ------------------- -As I continue to learn Rust, I plan to implement more features of RST into the raw file displays. For example, -embedding images. I want to strike a balance between the aesthetic of a terminal and ease of use of a website. +As I continue to learn Rust, I plan to implement more features of RST into the raw file displays. ~~For example, +embedding images~~ (now onto text formatting...). I want to strike a balance between the aesthetic of a terminal and +ease of use of a website. diff --git a/templates/listing.html.tera b/templates/listing.html.tera index be94fcc..32786ca 100644 --- a/templates/listing.html.tera +++ b/templates/listing.html.tera @@ -5,8 +5,8 @@ ls {{ page_data.site_file.link_name }} {% endblock command %} {% block content %} -{% for link in page_data.links %}
+{% for link in page_data.links %} {{ link.link_name }}   {% endfor %}