1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! *The documentation is still a work in progress, so if you have questions,
//! you are welcome to [create an issue](https://github.com/emirror-de/html5-picture). :-)*
//!
//! ## Purpose
//!
//! Supports the binary within this package.
//! Contains functions to easily generate different sizes of a picture that
//! can be used on webpages. Also offers the possibility to convert them into webp
//! format and is able to create `<picture>` tags for the given images.
//!
//! Currently this crate is only capable of converting `png` files to webp using
//! `cwebp`.
//! So make sure that webp is installed on your computer.
//!
//! ## Installation
//!
//! The binary can be installed via `cargo install html5-picture`. As stated
//! before, make sure webp is installed before using.
//!
//! ## Usage
//!
//! Use `html5-picture --help` for an overview of all parameters.
//!
//! ## Examples
//!
//! ### Conversion with three scales and 70% quality
//! If you want to create three different sizes of the images in `./assets`
//! with a conversion quality of 70%, enter the following command:
//!
//! ```bash
//! html5-picture ./assets 3 -q 70
//! ```
//!
//! This will convert your images and save them to `./assets-html5picture`.
//! This folder is also the working directory make sure to not modify it while
//! the application is running.
//!
//! ### Conversion with given installation folder
//! If you pass `-i <folder_name>` as parameter, the resulting files are
//! moved from the working directory to the given `<folder_name>` after conversion
//! and scaling.
//!
//! ```bash
//! html5-picture ./assets 3 -q 100 -i ./assets-build
//! ```
//!
//! In this example the images are installted to `./assets-build`.
//!
//! ### Force overwriting
//! Using the `-f` or `--force-overwrite` flag will overwrite existing webp or
//! HTML5 picture tag files.
//!
//! ```bash
//! html5-picture ./assets 3 -q 100 -i ./dist -f
//! ```
//!
//! ### Writing picture tag files to disk
//! With the `-p` option, it is possible to save the `<picture>` tags to disk.
//! However it is recommended to use it in combination with -m, which sets the
//! mountpoint in your tag files for you.
//!
//! ```bash
//! html5-picture ./assets 4 -i ./dist -p ./html5-tags -m /some/web-server/mountpoint
//! ```
//!
//! ### Read input files by JSON
//! **Upcoming feature.**
//! The pictures can be defined using JSON format. `html5-picture` will read it
//! from stdin. This enables definition of all attributes such as `alt` per image.
#[deny(missing_docs)]
#[deny(rustdoc::missing_crate_level_docs)]
#[deny(rustdoc::broken_intra_doc_links)]
#[deny(rustdoc::private_intra_doc_links)]
use {
    crate::core::{
        collect_file_names,
        copy_originals_to_output,
        create_all_output_directories,
        install_images_into,
        process_images,
        save_html_picture_tags,
        Config,
        State,
    },
    indicatif::ProgressBar,
    log::error,
    queue::Queue,
    std::path::PathBuf,
    walkdir::WalkDir,
};

/// Contains default functions and traits.
pub mod core;

/// Generic helper functions.
pub mod utils;

/// Support for webp format. Used mainly for conversion.
pub mod webp;

/// Path processing that is required for ```html5_picture```
pub mod path;

/// Functions operating on the filesystem that is required for ```html5_picture```
pub mod fs;

/// HTML5 related functions, such as creation of picture tags.
pub mod html5;

/// Determines if the given input filename contains a .png extension.
pub fn is_png(input: &PathBuf) -> bool {
    match input.extension() {
        Some(s) => match s.to_str() {
            None => false,
            Some(v) => v == "png",
        },
        None => false,
    }
}

/// Collects all png file names that are stored in the ```input_dir```.
pub fn collect_png_file_names(
    input_dir: &PathBuf,
    progressbar: Option<ProgressBar>,
) -> Vec<PathBuf> {
    let mut file_names = vec![];
    for entry in WalkDir::new(&input_dir) {
        // unwrap the entry
        let entry = if let Err(msg) = &entry {
            error!("{}", msg.to_string());
            continue;
        } else {
            entry.unwrap()
        };
        let entry = entry.into_path();

        if let Some(ref pb) = progressbar {
            pb.tick();
        }

        if !is_png(&entry) {
            continue;
        }
        file_names.push(entry);
    }
    file_names
}

/// The main function of the binary. Executes all required steps for copying,
/// conversion and installationn of the source images.
pub fn run(config: Config) {
    if !&config.input_dir.exists() {
        error!("Input directory does not exist!");
        return;
    }
    match &config.scaled_images_count {
        0 => {
            error!("Minimum scaled images count is 1!");
            return;
        }
        _ => (),
    }

    // add all default processes
    let mut q: Queue<fn(&mut State)> = Queue::new();
    q.queue(collect_file_names).unwrap();
    q.queue(create_all_output_directories).unwrap();
    q.queue(copy_originals_to_output).unwrap();

    // finally add processing step
    q.queue(process_images).unwrap();

    // optional steps
    if let Some(_) = &config.install_images_into {
        q.queue(install_images_into).unwrap();
    }
    if let Some(_) = &config.picture_tags_output_folder {
        q.queue(save_html_picture_tags).unwrap();
    }

    let mut s = State::new(config, q.len());

    while let Some(step_function) = s.dequeue(&mut q) {
        step_function(&mut s);
    }
}