basic image HTML rendering. Current tests pass!
This commit is contained in:
parent
bc33331dae
commit
9434eb835d
6 changed files with 156 additions and 113 deletions
|
|
@ -102,13 +102,14 @@ impl TryFrom<&AlbumDir> for AlbumContext {
|
|||
}
|
||||
|
||||
/// A Tera context for slide (individual image) pages
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Debug)]
|
||||
struct SlideContext {
|
||||
// TODO: Path or String?
|
||||
// Path required to get back to the root album
|
||||
root_path: PathBuf,
|
||||
image: Image,
|
||||
prev_image: Image,
|
||||
next_image: Image,
|
||||
prev_image: Option<Image>,
|
||||
next_image: Option<Image>,
|
||||
}
|
||||
|
||||
pub fn generate(root_path: &PathBuf) -> anyhow::Result<PathBuf> {
|
||||
|
|
@ -120,6 +121,7 @@ pub fn generate(root_path: &PathBuf) -> anyhow::Result<PathBuf> {
|
|||
env::set_current_dir(root_path)?;
|
||||
let album = AlbumDir::try_from(root_path)?;
|
||||
|
||||
fs::create_dir(&config.output_dir)?;
|
||||
copy_static(&config)?;
|
||||
generate_images(&config, &album)?;
|
||||
generate_html(&config, &album)?;
|
||||
|
|
@ -129,6 +131,13 @@ pub fn generate(root_path: &PathBuf) -> anyhow::Result<PathBuf> {
|
|||
}
|
||||
|
||||
fn copy_static(config: &Config) -> anyhow::Result<()> {
|
||||
let dst = &config.output_dir.join("static");
|
||||
log::info!("Copying static files from _static to {}", dst.display());
|
||||
fs_extra::dir::copy(
|
||||
"_static",
|
||||
dst,
|
||||
&fs_extra::dir::CopyOptions::new().content_only(true),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -139,6 +148,15 @@ fn generate_images(config: &Config, album: &AlbumDir) -> anyhow::Result<()> {
|
|||
for img in album.iter() {
|
||||
let orig_image = image::open(&img.path)?;
|
||||
|
||||
let orig_path = output_path.join(&img.path);
|
||||
log::info!(
|
||||
"Copying original {} -> {}",
|
||||
img.path.display(),
|
||||
orig_path.display()
|
||||
);
|
||||
fs::create_dir_all(orig_path.parent().unwrap_or(Path::new("")))?;
|
||||
orig_image.save(&orig_path)?;
|
||||
|
||||
let thumb_path = output_path.join(&img.thumb_path);
|
||||
log::info!(
|
||||
"Resizing {} -> {}",
|
||||
|
|
@ -180,7 +198,6 @@ fn generate_html(config: &Config, album: &AlbumDir) -> anyhow::Result<()> {
|
|||
.ok_or(anyhow!("Missing _templates dir in album dir"))?,
|
||||
)?;
|
||||
|
||||
// Queue of album dir and depth (distance from root AlbumDir)
|
||||
let mut dir_queue: VecDeque<&AlbumDir> = VecDeque::from([album]);
|
||||
while let Some(album) = dir_queue.pop_front() {
|
||||
let html_path = output_path.join(&album.path).join("index.html");
|
||||
|
|
@ -197,5 +214,37 @@ fn generate_html(config: &Config, album: &AlbumDir) -> anyhow::Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
let all_images: Vec<&Image> = album.iter().collect();
|
||||
for (pos, img) in all_images.iter().enumerate() {
|
||||
let img: &Image = *img;
|
||||
let prev_image: Option<&Image> = match pos {
|
||||
0 => None,
|
||||
n => Some(&all_images[n - 1]),
|
||||
};
|
||||
let next_image: Option<&Image> = all_images.get(pos + 1).map(|i| *i);
|
||||
|
||||
// Find the path to the root by counting the parts of the path
|
||||
let mut path_to_root = PathBuf::new();
|
||||
if let Some(parent) = img.path.parent() {
|
||||
let mut parent = parent.to_path_buf();
|
||||
while parent.pop() {
|
||||
path_to_root = path_to_root.join("..");
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Rendering image {}", img.html_path.display());
|
||||
let ctx = SlideContext {
|
||||
root_path: path_to_root,
|
||||
image: img.clone(),
|
||||
prev_image: prev_image.cloned(),
|
||||
next_image: next_image.cloned(),
|
||||
};
|
||||
log::debug!("Image context: {ctx:?}");
|
||||
fs::write(
|
||||
output_path.join(&img.html_path),
|
||||
tera.render("photo.html", &tera::Context::from_serialize(&ctx)?)?,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::anyhow;
|
||||
use image::ImageReader;
|
||||
use serde::Serialize;
|
||||
use std::ffi::OsString;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::slice::Iter;
|
||||
|
|
@ -21,6 +21,7 @@ pub struct AlbumDir {
|
|||
|
||||
impl AlbumDir {
|
||||
/// Returns an iterator over all images in the album and subalbums
|
||||
// TODO: Rename to iter_images() and make separate one for dirs?
|
||||
pub fn iter(&self) -> AlbumIter {
|
||||
AlbumIter::new(self)
|
||||
}
|
||||
|
|
@ -145,10 +146,11 @@ impl<'a> Iterator for AlbumIter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, PartialEq, Eq, Serialize)]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize)]
|
||||
pub struct Image {
|
||||
/// Path to the image, relative to the root album
|
||||
pub path: PathBuf,
|
||||
pub filename: OsString,
|
||||
|
||||
/// Text description of the image which is displayed below it on the HTML page
|
||||
pub description: String,
|
||||
|
|
@ -163,17 +165,25 @@ pub struct Image {
|
|||
|
||||
impl Image {
|
||||
pub fn new(path: PathBuf, description: String) -> anyhow::Result<Self> {
|
||||
let filename = path
|
||||
.file_name()
|
||||
.ok_or(anyhow!(
|
||||
"Image path {} is missing a filename",
|
||||
path.display()
|
||||
))?
|
||||
.into();
|
||||
let thumb_filename = Self::slide_filename(&path, "thumb", true)?;
|
||||
let thumb_path = Self::slide_path(&path, "thumb")?;
|
||||
let thumb_path = Self::slide_path(&path, &thumb_filename);
|
||||
let screen_filename = Self::slide_filename(&path, "screen", true)?;
|
||||
let screen_path = Self::slide_path(&path, "screen")?;
|
||||
let screen_path = Self::slide_path(&path, &screen_filename);
|
||||
// TODO: add "slides" in html path?
|
||||
let html_filename = Self::slide_filename(&path, "html", false)?;
|
||||
let html_path = path.with_extension("html");
|
||||
let html_path = Self::slide_path(&path, &html_filename);
|
||||
|
||||
Ok(Image {
|
||||
path,
|
||||
description,
|
||||
filename,
|
||||
thumb_filename,
|
||||
thumb_path,
|
||||
screen_filename,
|
||||
|
|
@ -209,30 +219,13 @@ impl Image {
|
|||
Ok(new_name.into())
|
||||
}
|
||||
|
||||
/// Returns the path to the file in the slides dir with the given extention insert, e.g.
|
||||
/// "thumb" or "display"
|
||||
fn slide_path(path: &PathBuf, ext: &str) -> anyhow::Result<PathBuf> {
|
||||
let new_ext = match path.extension() {
|
||||
Some(e) => {
|
||||
ext.to_string()
|
||||
+ "."
|
||||
+ e.to_str().ok_or(anyhow!(
|
||||
"Image {} extension is not valid UTF-8",
|
||||
path.display()
|
||||
))?
|
||||
}
|
||||
None => ext.to_string(),
|
||||
};
|
||||
|
||||
let new_path = path.with_extension(new_ext);
|
||||
let new_name = new_path
|
||||
.file_name()
|
||||
.ok_or(anyhow!("Image {} missing a file name", path.display()))?;
|
||||
let parent = path
|
||||
.parent()
|
||||
.ok_or(anyhow!("Image {} has no parent dir", path.display()))?;
|
||||
|
||||
Ok(parent.join("slides").join(new_name))
|
||||
/// Returns the path to the file in the slides dir given the path to the original image
|
||||
fn slide_path(path: &PathBuf, file_name: &OsStr) -> PathBuf {
|
||||
let mut new_path = path.clone();
|
||||
new_path.pop();
|
||||
new_path.push("slides");
|
||||
new_path.push(&file_name);
|
||||
new_path
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue