convert_image_with_format resamples every key image to the device's key size with nearest-neighbour:
https://github.com/OpenActionAPI/rust-elgato-streamdeck/blob/main/src/images.rs#L29
let image = image.resize_exact(ws as u32, hs as u32, FilterType::Nearest);
This discards the antialiasing of whatever the caller drew. On a Stream Deck + the ratio is 144 → 120, i.e. 6:5, so it drops every sixth row and column and point-samples soft edges rather than averaging them. The result on the panel is stair-stepped diagonals, strokes whose width visibly alternates along their length, and small text that turns to mush.
I ran into this writing an OpenDeck plugin that draws its key faces as SVG. Rendering the same source image through the pipeline twice — once with Nearest and once with Lanczos3, everything else identical, including both JPEG passes — the Nearest output matches what my hardware shows, and the Lanczos3 output is clean. Nothing about the artwork changed between the two.
Key images are at most 200×200, so a proper filter is not worth optimising away here:
- let image = image.resize_exact(ws as u32, hs as u32, FilterType::Nearest);
+ // Nearest-neighbour discards the antialiasing on every key image. At the
+ // Stream Deck +'s 6:5 ratio (144 -> 120) it drops every sixth row and column
+ // and point-samples soft edges into stair-steps.
+ let image = if image.width() == ws as u32 && image.height() == hs as u32 {
+ image
+ } else {
+ image.resize_exact(ws as u32, hs as u32, FilterType::Lanczos3)
+ };
FilterType::Triangle would also be a large improvement if Lanczos3 is considered too heavy. The equality guard keeps the call free for callers that already hand over a correctly-sized image, which is the case worth optimising for.
Happy to open a PR if you'd like it in that shape.
convert_image_with_formatresamples every key image to the device's key size with nearest-neighbour:https://github.com/OpenActionAPI/rust-elgato-streamdeck/blob/main/src/images.rs#L29
This discards the antialiasing of whatever the caller drew. On a Stream Deck + the ratio is 144 → 120, i.e. 6:5, so it drops every sixth row and column and point-samples soft edges rather than averaging them. The result on the panel is stair-stepped diagonals, strokes whose width visibly alternates along their length, and small text that turns to mush.
I ran into this writing an OpenDeck plugin that draws its key faces as SVG. Rendering the same source image through the pipeline twice — once with
Nearestand once withLanczos3, everything else identical, including both JPEG passes — theNearestoutput matches what my hardware shows, and theLanczos3output is clean. Nothing about the artwork changed between the two.Key images are at most 200×200, so a proper filter is not worth optimising away here:
FilterType::Trianglewould also be a large improvement ifLanczos3is considered too heavy. The equality guard keeps the call free for callers that already hand over a correctly-sized image, which is the case worth optimising for.Happy to open a PR if you'd like it in that shape.