Compare commits

..
Author SHA1 Message Date
clyde d00820fae7 Merge branch 's-draw' into s-gray 2026-10-23 08:50:37 +11:00
clyde 4dc829e091 Merge branch 's-draw' into s-gray 2026-10-23 08:23:13 +11:00
clyde e31de889ef Merge branch 's-draw' into s-gray 2026-10-23 08:01:27 +11:00
clyde f7b2bb8c19 Merge branch 's-draw' into s-gray 2026-10-23 07:24:51 +11:00
clyde 066e95077a Merge branch 's-draw' into s-gray 2026-10-23 07:24:03 +11:00
clydeandClaude Opus 5.5 9ce82f98cc [runtime_image] Work out grayscale pixels with integer maths
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 05:52:49 +10:00
2 changed files with 38 additions and 1 deletions
@@ -116,7 +116,9 @@ void RuntimeImage::draw_pixel(int x, int y, const Color &color) {
}
case image::IMAGE_TYPE_GRAYSCALE: {
uint32_t pos = this->get_position_(x, y);
auto gray = static_cast<uint8_t>(0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b);
// 0.2125, 0.7154 and 0.0721 in 1/256ths, summing to 256 so white stays 255. Integer maths: the S3 has no
// double FPU
auto gray = static_cast<uint8_t>((54 * color.r + 183 * color.g + 19 * color.b) >> 8);
if (this->transparency_ == image::TRANSPARENCY_CHROMA_KEY) {
if (gray == 1) {
gray = 0;
@@ -0,0 +1,35 @@
#include <gtest/gtest.h>
#include <cstdint>
#include <cstdlib>
#include "esphome/components/runtime_image/runtime_image.h"
namespace esphome::runtime_image::testing {
class GrayscaleImage : public RuntimeImage {
public:
GrayscaleImage() : RuntimeImage(BMP, image::IMAGE_TYPE_GRAYSCALE, image::TRANSPARENCY_OPAQUE) {}
uint8_t pixel(int x) const { return this->buffer_[x]; }
};
// The integer weights stay within one step of the floating point formula they replace, and keep white at 255
TEST(GrayscalePixel, MatchesTheFloatingPointWeights) {
GrayscaleImage img;
ASSERT_GT(img.resize(256, 1), 0);
for (int r = 0; r < 256; r += 5) {
for (int g = 0; g < 256; g += 5) {
for (int b = 0; b < 256; b += 5) {
img.draw_pixel(0, 0, Color(r, g, b));
const int expected = static_cast<int>(0.2125 * r + 0.7154 * g + 0.0721 * b);
ASSERT_LE(std::abs(img.pixel(0) - expected), 1) << "r=" << r << " g=" << g << " b=" << b;
}
}
}
img.draw_pixel(1, 0, Color(255, 255, 255));
EXPECT_EQ(img.pixel(1), 255);
img.draw_pixel(2, 0, Color(0, 0, 0));
EXPECT_EQ(img.pixel(2), 0);
}
} // namespace esphome::runtime_image::testing