diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2025-11-27 22:03:32 +0100 |
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2025-11-27 22:03:32 +0100 |
| commit | db116a806c1b81c36a574eba9a4f3c472ddca11f (patch) | |
| tree | 69f840fea6279754a715c3c66b67c74d2c44f4aa | |
| parent | 58536c0aac7187a697ebfa56d8e4dd94b4a59cbe (diff) | |
| download | hittekaart-db116a806c1b81c36a574eba9a4f3c472ddca11f.tar.gz hittekaart-db116a806c1b81c36a574eba9a4f3c472ddca11f.tar.bz2 hittekaart-db116a806c1b81c36a574eba9a4f3c472ddca11f.zip | |
small speedup for colorize_tile
This brings
1. a color lookup table so we avoid re-computing the gradient every time
2. better iterating over the pixels, so we don't need an explicit
get_pixel_mut
| -rw-r--r-- | hittekaart/src/renderer/heatmap.rs | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/hittekaart/src/renderer/heatmap.rs b/hittekaart/src/renderer/heatmap.rs index 38a1543..6400e82 100644 --- a/hittekaart/src/renderer/heatmap.rs +++ b/hittekaart/src/renderer/heatmap.rs @@ -7,9 +7,10 @@ //! We then render the colored heatmap tiles in `Renderer::colorize()`, which provides us with //! colorful PNG data. use crossbeam_channel::Sender; -use image::{ImageBuffer, Luma, Pixel, RgbaImage}; +use image::{ImageBuffer, Luma, Pixel, Rgba, RgbaImage}; use nalgebra::{vector, Vector2}; use rayon::iter::ParallelIterator; +use std::iter; use super::{ super::{ @@ -119,25 +120,32 @@ fn merge_heat_counter(base: &mut HeatCounter, overlay: &HeatCounter) { for (tx, ty, source) in overlay.enumerate_tiles() { let target = base.tile_mut(tx, ty); for (t, s) in target.iter_mut().zip(source.iter()) { - *t += *s; + *t += *s; } } } -fn colorize_tile(tile: &ImageBuffer<Luma<u8>, Vec<u8>>, max: u32) -> RgbaImage { - let gradient = colorgrad::yl_or_rd(); +fn colorize_tile(tile: &ImageBuffer<Luma<u8>, Vec<u8>>, lut: &[Rgba<u8>]) -> RgbaImage { let mut result = ImageBuffer::from_pixel(tile.width(), tile.height(), [0, 0, 0, 0].into()); - for (x, y, pixel) in tile.enumerate_pixels() { + for (pixel, target) in tile.pixels().zip(result.pixels_mut()) { if pixel[0] > 0 { - let alpha = pixel[0] as f64 / max as f64; - let color = gradient.at(1.0 - alpha); - let target = result.get_pixel_mut(x, y); - *target = color.to_rgba8().into(); + *target = lut[usize::from(pixel[0])]; } } result } +fn prepare_lut(max: u8) -> Vec<Rgba<u8>> { + let gradient = colorgrad::yl_or_rd(); + iter::once([0, 0, 0, 0].into()) + .chain((1..=max).map(|count| { + let alpha = count as f64 / max as f64; + let color = gradient.at(1.0 - alpha); + color.to_rgba8().into() + })) + .collect() +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Renderer; @@ -193,10 +201,13 @@ impl super::Renderer for Renderer { return Ok(()); } + // max is a u8, so at most we have 256 colors to compute. We can handle that. + let color_lut = prepare_lut(max); + layer .into_parallel_tiles() .try_for_each_with(tx, |tx, (tile_x, tile_y, tile)| { - let colorized = colorize_tile(&tile, max.into()); + let colorized = colorize_tile(&tile, &color_lut); let data = layer::compress_png_as_bytes(&colorized)?; tx.send(RenderedTile { x: tile_x, |
