Skip to content

Commit 04e18c0

Browse files
nocdurobudziq
authored andcommitted
Add rayon thumbnail generation example
1 parent 255affd commit 04e18c0

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

src/concurrency.md

+86
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
|--------|--------|------------|
55
| [Mutate the elements of an array in parallel][ex-rayon-iter-mut] | [![rayon-badge]][rayon] | [![cat-concurrency-badge]][cat-concurrency] |
66
| [Sort a vector in parallel][ex-rayon-parallel-sort] | [![rayon-badge]][rayon] [![rand-badge]][rand] | [![cat-concurrency-badge]][cat-concurrency] |
7+
| [Generate jpg thumbnails in parallel][ex-rayon-thumbnails] | [![rayon-badge]][rayon] [![glob-badge]][glob] [![image-badge]][image] | [![cat-concurrency-badge]][cat-concurrency][![cat-filesystem-badge]][cat-filesystem] |
78
| [Spawn a short-lived thread][ex-crossbeam-spawn] | [![crossbeam-badge]][crossbeam] | [![cat-concurrency-badge]][cat-concurrency] |
89
| [Draw fractal dispatching work to a thread pool][ex-threadpool-fractal] | [![threadpool-badge]][threadpool] [![num-badge]][num] [![num_cpus-badge]][num_cpus] [![image-badge]][image] | [![cat-concurrency-badge]][cat-concurrency][![cat-science-badge]][cat-science][![cat-rendering-badge]][cat-rendering] |
910

@@ -70,7 +71,89 @@ fn main() {
7071
}
7172
```
7273

74+
[ex-rayon-thumbnails]: #ex-rayon-thumbnails
75+
<a name="ex-rayon-thumbnails"></a>
76+
## Generate jpg thumbnails in parallel
7377

78+
[![rayon-badge]][rayon] [![glob-badge]][glob] [![image-badge]][image] [![cat-concurrency-badge]][cat-concurrency] [![cat-filesystem-badge]][cat-filesystem]
79+
80+
This example generates thumbnails for all .jpg in the current directory and saves them in a new folder called `thumbnails`.
81+
82+
Files are found using [`glob::glob_with`] to match case insensitively on both `.jpg` and `.JPG`. `rayon` is then used to resize images in parallel using [`par_iter`] along with the `make_thumbnail()` helper function which internally uses [`DynamicImage::resize`].
83+
84+
```rust,no_run
85+
# #[macro_use]
86+
# extern crate error_chain;
87+
extern crate glob;
88+
extern crate image;
89+
extern crate rayon;
90+
91+
use std::path::Path;
92+
use std::fs::{create_dir_all, File};
93+
94+
# use error_chain::ChainedError;
95+
use glob::{glob_with, MatchOptions};
96+
use image::{FilterType, ImageError};
97+
use rayon::prelude::*;
98+
99+
# error_chain! {
100+
# foreign_links {
101+
# Image(ImageError);
102+
# Io(std::io::Error);
103+
# Glob(glob::PatternError);
104+
# }
105+
# }
106+
107+
fn run() -> Result<()> {
108+
// find all files in current directory that have a .jpg extension
109+
// use the default MatchOptions so the search is case insensitive
110+
let options: MatchOptions = Default::default();
111+
let files: Vec<_> = glob_with("*.jpg", &options)?
112+
.filter_map(|x| x.ok())
113+
.collect();
114+
115+
if files.len() == 0 {
116+
bail!("No .jpg files found in current directory");
117+
}
118+
119+
let thumb_dir = "thumbnails";
120+
create_dir_all(thumb_dir)?;
121+
122+
println!("Saving {} thumbnails into '{}'...", files.len(), thumb_dir);
123+
124+
let image_failures: Vec<_> = files
125+
.par_iter()
126+
.map(|path| {
127+
make_thumbnail(path, thumb_dir, 300)
128+
.map_err(|e| e.chain_err(|| path.display().to_string()))
129+
})
130+
.filter_map(|x| x.err())
131+
.collect();
132+
133+
for failure in &image_failures {
134+
println!("{}", failure.display_chain());
135+
}
136+
137+
println!("{} thumbnails saved successfully", files.len() - image_failures.len());
138+
Ok(())
139+
}
140+
141+
/// Resize `original` to have a maximum dimension of `longest_edge` and save the
142+
/// resized image to the `thumb_dir` folder
143+
fn make_thumbnail<PA, PB>(original: PA, thumb_dir: PB, longest_edge: u32) -> Result<()>
144+
where
145+
PA: AsRef<Path>,
146+
PB: AsRef<Path>,
147+
{
148+
let img = image::open(original.as_ref())?;
149+
let fout = &mut File::create(thumb_dir.as_ref().join(original))?;
150+
151+
Ok(img.resize(longest_edge, longest_edge, FilterType::Nearest)
152+
.save(fout, image::JPEG)?)
153+
}
154+
#
155+
# quick_main!(run);
156+
```
74157

75158
[ex-crossbeam-spawn]: #ex-crossbeam-spawn
76159
<a name="ex-crossbeam-spawn"></a>
@@ -236,6 +319,8 @@ fn run() -> Result<()> {
236319

237320
<!-- API Reference -->
238321

322+
[`DynamicImage::resize`]: https://docs.rs/image/*/image/enum.DynamicImage.html#method.resize
323+
[`glob::glob_with`]: https://docs.rs/glob/*/glob/fn.glob_with.html
239324
[`ImageBuffer::new`]: https://docs.rs/image/*/image/struct.ImageBuffer.html#method.new
240325
[`ImageBuffer::put_pixel`]: https://docs.rs/image/*/image/struct.ImageBuffer.html#method.put_pixel
241326
[`ImageBuffer::save`]: https://docs.rs/image/*/image/struct.ImageBuffer.html#method.save
@@ -249,6 +334,7 @@ fn run() -> Result<()> {
249334
[`mpsc::channel`]: https://doc.rust-lang.org/std/sync/mpsc/fn.channel.html
250335
[`multiple options`]: https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html
251336
[`num_cpus::get`]: https://docs.rs/num_cpus/*/num_cpus/fn.get.html
337+
[`par_iter`]: https://docs.rs/rayon/*/rayon/iter/trait.IntoParallelRefIterator.html#tymethod.par_iter
252338
[`par_iter_mut`]: https://docs.rs/rayon/*/rayon/iter/trait.IntoParallelRefMutIterator.html#tymethod.par_iter_mut
253339
[`par_sort_unstable`]: https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html#method.par_sort_unstable
254340

src/intro.md

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ community. It needs and welcomes help. For details see
6161
|--------|--------|------------|
6262
| [Mutate the elements of an array in parallel][ex-rayon-iter-mut] | [![rayon-badge]][rayon] | [![cat-concurrency-badge]][cat-concurrency] |
6363
| [Sort a vector in parallel][ex-rayon-parallel-sort] | [![rayon-badge]][rayon] [![rand-badge]][rand] | [![cat-concurrency-badge]][cat-concurrency] |
64+
| [Generate jpg thumbnails in parallel][ex-rayon-thumbnails] | [![rayon-badge]][rayon] [![glob-badge]][glob] [![image-badge]][image] | [![cat-concurrency-badge]][cat-concurrency][![cat-filesystem-badge]][cat-filesystem] |
6465
| [Spawn a short-lived thread][ex-crossbeam-spawn] | [![crossbeam-badge]][crossbeam] | [![cat-concurrency-badge]][cat-concurrency] |
6566
| [Draw fractal dispatching work to a thread pool][ex-threadpool-fractal] | [![threadpool-badge]][threadpool] [![num-badge]][num] [![num_cpus-badge]][num_cpus] [![image-badge]][image] | [![cat-concurrency-badge]][cat-concurrency][![cat-science-badge]][cat-science][![cat-rendering-badge]][cat-rendering] |
6667

@@ -166,6 +167,7 @@ community. It needs and welcomes help. For details see
166167
[ex-random-port-tcp]: net.html#ex-random-port-tcp
167168
[ex-rayon-iter-mut]: concurrency.html#ex-rayon-iter-mut
168169
[ex-rayon-parallel-sort]: concurrency.html#ex-rayon-parallel-sort
170+
[ex-rayon-thumbnails]: concurrency.html#ex-rayon-thumbnails
169171
[ex-regex-filter-log]: basics.html#ex-regex-filter-log
170172
[ex-rest-custom-params]: net.html#ex-rest-custom-params
171173
[ex-rest-get]: net.html#ex-rest-get

0 commit comments

Comments
 (0)