aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2023-01-12 23:59:46 +0100
committerDaniel Schadt <kingdread@gmx.de>2023-01-12 23:59:46 +0100
commit7bbba155f10ce1344724ea00ca70c4d3bb469272 (patch)
treea370a39a8ad226e27bc1c4f3957c993ed17ad816 /src
parentdef44c6e969f1027da82e4130a82db7e4916ba86 (diff)
downloadhittekaart-7bbba155f10ce1344724ea00ca70c4d3bb469272.tar.gz
hittekaart-7bbba155f10ce1344724ea00ca70c4d3bb469272.tar.bz2
hittekaart-7bbba155f10ce1344724ea00ca70c4d3bb469272.zip
parallelize PNG encoding
This gives a massive speedup
Diffstat (limited to 'src')
-rw-r--r--src/layer.rs13
-rw-r--r--src/main.rs2
-rw-r--r--src/renderer.rs40
3 files changed, 36 insertions, 19 deletions
diff --git a/src/layer.rs b/src/layer.rs
index a8057a0..ff69f7d 100644
--- a/src/layer.rs
+++ b/src/layer.rs
@@ -12,6 +12,7 @@ use image::{
ColorType, ImageBuffer, ImageEncoder, Pixel, RgbaImage,
};
use num_traits::Zero;
+use rayon::iter::{IntoParallelIterator, ParallelIterator};
pub const TILE_HEIGHT: u64 = 256;
pub const TILE_WIDTH: u64 = 256;
@@ -104,6 +105,18 @@ impl<P: Pixel> TileLayer<P> {
}
}
+impl<P> TileLayer<P>
+where
+ P: Pixel + Send,
+ P::Subpixel: Send,
+{
+ pub fn into_parallel_tiles(
+ self,
+ ) -> impl ParallelIterator<Item = (u64, u64, ImageBuffer<P, Vec<P::Subpixel>>)> {
+ IntoParallelIterator::into_par_iter(self.tiles).map(|((x, y), t)| (x, y, t))
+ }
+}
+
pub fn compress_png<P: AsRef<Path>>(image: &RgbaImage, path: P) -> Result<()> {
let outstream = BufWriter::new(File::create(path)?);
let encoder =
diff --git a/src/main.rs b/src/main.rs
index 1859243..269d95c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -39,7 +39,7 @@ fn main() -> Result<()> {
let bar = ProgressBar::new(counter.tile_count().try_into().unwrap())
.with_style(progress_style.clone());
bar.set_prefix("Saving heat tiles");
- renderer::lazy_colorization(&counter, &target, |x| bar.inc(x.try_into().unwrap()))?;
+ renderer::lazy_colorization(counter, &target, |x| bar.inc(x.try_into().unwrap()))?;
bar.finish();
}
diff --git a/src/renderer.rs b/src/renderer.rs
index cece8f3..2f29828 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -3,6 +3,7 @@ use std::{fs, path::Path};
use color_eyre::eyre::{bail, Result};
use image::{ImageBuffer, Luma, Pixel, RgbaImage};
use nalgebra::{vector, Vector2};
+use rayon::iter::ParallelIterator;
use super::{
gpx::Coordinates,
@@ -131,10 +132,10 @@ fn colorize_tile(tile: &ImageBuffer<Luma<u8>, Vec<u8>>, max: u32) -> RgbaImage {
/// rendering the next one.
///
/// This has a way lower memory usage than [`colorize_heatcounter`].
-pub fn lazy_colorization<P: AsRef<Path>, F: FnMut(usize)>(
- layer: &HeatCounter,
+pub fn lazy_colorization<P: AsRef<Path>, F: Fn(usize) + Send + Sync>(
+ layer: HeatCounter,
base_dir: P,
- mut progress_callback: F,
+ progress_callback: F,
) -> Result<()> {
let base_dir = base_dir.as_ref();
let max = layer.pixels().map(|l| l.0[0]).max().unwrap_or_default();
@@ -142,27 +143,30 @@ pub fn lazy_colorization<P: AsRef<Path>, F: FnMut(usize)>(
return Ok(());
}
- for (tile_x, tile_y, tile) in layer.enumerate_tiles() {
- let colorized = colorize_tile(tile, max.into());
- let folder = base_dir.join(tile_x.to_string());
- let metadata = folder.metadata();
- match metadata {
- Err(_) => fs::create_dir(&folder)?,
- Ok(m) if !m.is_dir() => bail!("Output path is not a directory"),
- _ => {}
- }
- let file = folder.join(format!("{tile_y}.png"));
- layer::compress_png(&colorized, file)?;
- progress_callback(1);
- }
+ layer
+ .into_parallel_tiles()
+ .try_for_each(|(tile_x, tile_y, tile)| {
+ let colorized = colorize_tile(&tile, max.into());
+ let folder = base_dir.join(tile_x.to_string());
+ let metadata = folder.metadata();
+ match metadata {
+ Err(_) => fs::create_dir_all(&folder)?,
+ Ok(m) if !m.is_dir() => bail!("Output path is not a directory"),
+ _ => {}
+ }
+ let file = folder.join(format!("{tile_y}.png"));
+ layer::compress_png(&colorized, file)?;
+ progress_callback(1);
+ Ok(())
+ })?;
Ok(())
}
/// Renders the heat counter for the given zoom level and track points.
-pub fn render_heatcounter<F: FnMut(usize)>(
+pub fn render_heatcounter<F: Fn(usize) + Send + Sync>(
zoom: u32,
tracks: &[Vec<Coordinates>],
- mut progress_callback: F,
+ progress_callback: F,
) -> HeatCounter {
let mut heatcounter = TileLayer::from_pixel([0].into());