diff options
| -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, |
