diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2023-01-12 23:59:46 +0100 | 
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2023-01-12 23:59:46 +0100 | 
| commit | 7bbba155f10ce1344724ea00ca70c4d3bb469272 (patch) | |
| tree | a370a39a8ad226e27bc1c4f3957c993ed17ad816 /src | |
| parent | def44c6e969f1027da82e4130a82db7e4916ba86 (diff) | |
| download | hittekaart-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.rs | 13 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/renderer.rs | 40 | 
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());  | 
