aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2025-11-27 22:03:32 +0100
committerDaniel Schadt <kingdread@gmx.de>2025-11-27 22:03:32 +0100
commitdb116a806c1b81c36a574eba9a4f3c472ddca11f (patch)
tree69f840fea6279754a715c3c66b67c74d2c44f4aa
parent58536c0aac7187a697ebfa56d8e4dd94b4a59cbe (diff)
downloadhittekaart-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.rs31
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,