Added RST image parsing
+ Added DIP project
This commit is contained in:
parent
9fbad90eb8
commit
68ecb118a9
31
src/main.rs
31
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<T> = std::result::Result<T, JSiteError>;
|
||||
|
||||
@ -117,7 +118,7 @@ fn get_pages(path: &str, pages: &mut Vec<SiteFile>) -> 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<SiteFile>) -> io::Result<()> {
|
||||
/// * `page_name` - file to look for
|
||||
fn get_page(path: &Path) -> PageResult<SiteFile> {
|
||||
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<SiteFile> {
|
||||
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<SiteFile> = 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", "<br>");
|
||||
|
@ -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<String, String> = 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!("<a class=\"link\" href=\"{}\">{}</a>", link, &cap[1])
|
||||
});
|
||||
|
||||
output.to_string()
|
||||
}
|
111
src/rst_parser/mod.rs
Normal file
111
src/rst_parser/mod.rs
Normal file
@ -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<String>,
|
||||
/// Width
|
||||
width: Option<String>,
|
||||
/// Alt Text
|
||||
alt: Option<String>,
|
||||
/// Align (not implemented)
|
||||
#[allow(dead_code)]
|
||||
align: Option<String>,
|
||||
}
|
||||
|
||||
impl RSTImage {
|
||||
/// Convert to HTML img tag
|
||||
fn to_html(&self) -> String {
|
||||
let mut html = format!("<img src=\"{}\"", self.image_file);
|
||||
let mut style = "".to_string();
|
||||
|
||||
if let Some(alt) = &self.alt {
|
||||
html = format!("{} {}", html, alt);
|
||||
}
|
||||
|
||||
if let Some(height) = &self.height {
|
||||
style = format!("{}height;{};", style, height);
|
||||
}
|
||||
if let Some(width) = &self.width {
|
||||
style = format!("{}width:{};", style, width);
|
||||
}
|
||||
|
||||
html = format!("{} style=\"{}\">", 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<Self, Self::Error> {
|
||||
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<String, RSTError> {
|
||||
let re_link_ref = Regex::new(r"\n?.. _(.*): (.*)\n")?;
|
||||
let mut link_map: HashMap<String, String> = 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!("<a class=\"link\" href=\"{}\">{}</a>", 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<String, RSTError> {
|
||||
let re_image = Regex::new(
|
||||
r".. image:: (?P<file_name>.*)\n( *((:height: (?P<height>.*))|(:width: (?P<width>.*))|(:scale: (?P<scale>.*%))|(:alt: (?P<alt>.*))|(:align: (?P<align>.*)))\n)*",
|
||||
)?;
|
||||
|
||||
Ok(re_image
|
||||
.replace_all(string, |cap: &Captures| RSTImage::try_from(cap).unwrap().to_html())
|
||||
.to_string())
|
||||
}
|
28
src/rst_parser/rst_error.rs
Normal file
28
src/rst_parser/rst_error.rs
Normal file
@ -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<regex::Error> 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),
|
||||
}
|
||||
}
|
||||
}
|
33
static/raw_rst/projects/motion_detector.rst
Normal file
33
static/raw_rst/projects/motion_detector.rst
Normal file
@ -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
|
||||
|
@ -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.
|
||||
|
@ -5,8 +5,8 @@ ls {{ page_data.site_file.link_name }}
|
||||
{% endblock command %}
|
||||
|
||||
{% block content %}
|
||||
{% for link in page_data.links %}
|
||||
<br>
|
||||
{% for link in page_data.links %}
|
||||
<a class="link" href="{{ page_data.site_file.link_name}}/{{ link.link_name }}">{{ link.link_name }}</a>
|
||||
{% endfor %}
|
||||
<br>
|
||||
|
Loading…
x
Reference in New Issue
Block a user